From 40d262e091d43b15c082260b7279daf4e89b2799 Mon Sep 17 00:00:00 2001 From: luohairen <3399054449@qq.com> Date: 星期五, 29 十一月 2024 07:48:36 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- common/src/main/java/com/ycl/common/utils/DateUtils.java | 35 common/src/main/java/com/ycl/common/enums/business/ProjectCategoryEnum.java | 51 common/src/main/java/com/ycl/common/utils/excel/core/ExcelResult.java | 26 common/src/main/java/com/ycl/common/utils/excel/service/DictService.java | 67 + common/src/main/java/com/ycl/common/utils/excel/core/DropDownOptions.java | 149 ++ common/src/main/java/com/ycl/common/utils/excel/core/ExcelListener.java | 14 business/src/main/java/com/ycl/service/impl/ProjectInvestmentPolicyComplianceServiceImpl.java | 2 common/src/main/java/com/ycl/common/utils/excel/annotation/ExcelDictFormat.java | 32 business/src/main/java/com/ycl/domain/query/ProjectInfoQuery.java | 36 common/src/main/java/com/ycl/common/utils/excel/OutputExcelUtils.java | 217 +++ common/src/main/java/com/ycl/common/utils/excel/core/DefaultExcelResult.java | 73 + business/src/main/resources/mapper/ProjectInfoMapper.xml | 170 +- common/src/main/java/com/ycl/common/utils/excel/utils/ValidatorUtils.java | 36 common/src/main/java/com/ycl/common/utils/CopyUtils.java | 48 common/src/main/java/com/ycl/common/utils/excel/core/CellMergeStrategy.java | 157 ++ business/src/main/java/com/ycl/domain/excel/ProjectExcelTemplate.java | 655 +++++++++++ business/src/main/java/com/ycl/domain/vo/ProjectVO.java | 17 common/src/main/java/com/ycl/common/utils/excel/core/ExcelDownHandler.java | 373 ++++++ business/src/main/java/com/ycl/domain/vo/ProjectInfoVO.java | 26 common/src/main/java/com/ycl/common/utils/excel/utils/JsonUtils.java | 169 ++ common/src/main/java/com/ycl/common/utils/excel/convert/ExcelEnumConvert.java | 87 + common/src/main/java/com/ycl/common/utils/excel/convert/ExcelBigNumberConvert.java | 52 business/src/main/java/com/ycl/domain/entity/ProjectInfo.java | 6 common/src/main/java/com/ycl/common/utils/excel/annotation/CellMerge.java | 29 business/src/main/java/com/ycl/controller/ProjectInfoController.java | 17 business/src/main/java/com/ycl/service/impl/ProjectInfoServiceImpl.java | 84 + common/src/main/java/com/ycl/common/utils/excel/utils/ReflectUtils.java | 55 common/src/main/java/com/ycl/common/utils/excel/utils/StringUtils.java | 323 +++++ common/pom.xml | 9 common/src/main/java/com/ycl/common/utils/excel/annotation/ExcelEnumFormat.java | 30 system/pom.xml | 6 common/src/main/java/com/ycl/common/utils/excel/core/DefaultExcelListener.java | 104 + common/src/main/java/com/ycl/common/utils/excel/utils/StreamUtils.java | 282 ++++ 33 files changed, 3,335 insertions(+), 102 deletions(-) diff --git a/business/src/main/java/com/ycl/controller/ProjectInfoController.java b/business/src/main/java/com/ycl/controller/ProjectInfoController.java index f2e314c..768ed26 100644 --- a/business/src/main/java/com/ycl/controller/ProjectInfoController.java +++ b/business/src/main/java/com/ycl/controller/ProjectInfoController.java @@ -4,6 +4,8 @@ import com.ycl.common.group.Add; import com.ycl.common.group.Update; import com.ycl.common.utils.ProjectCodeGenerator; +import com.ycl.common.utils.excel.OutputExcelUtils; +import com.ycl.domain.excel.ProjectExcelTemplate; import com.ycl.domain.form.DocumentInfoForm; import com.ycl.domain.form.ProjectInfoForm; import com.ycl.domain.query.ProjectInfoQuery; @@ -14,7 +16,9 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.NotEmpty; +import java.io.IOException; import java.util.List; /** @@ -104,4 +108,17 @@ public Result getManagerFlag(@PathVariable("recordId") Integer recordId) { return projectInfoService.getManagerFlag(recordId); } + + /** + * 瀵煎嚭妯℃澘 + * @param response + * @return + */ + @PostMapping("/export/template") + public void exportTemplate(HttpServletResponse response, + @RequestBody List<String> fieldList + ) throws IOException { + OutputExcelUtils.export(response, "瀵煎叆妯℃澘", "椤圭洰淇℃伅", null, ProjectExcelTemplate.class ,fieldList); + } + } diff --git a/business/src/main/java/com/ycl/domain/entity/ProjectInfo.java b/business/src/main/java/com/ycl/domain/entity/ProjectInfo.java index d5eec5c..2029fa3 100644 --- a/business/src/main/java/com/ycl/domain/entity/ProjectInfo.java +++ b/business/src/main/java/com/ycl/domain/entity/ProjectInfo.java @@ -49,9 +49,9 @@ /** 鎶曡祫绫诲埆锛�0浼佷笟鎶曡祫锛�1鏀垮簻鎶曡祫锛�2澶栧晢鎶曡祫锛�3澧冨鎶曡祫锛� */ private String investType; - @TableField("project_phase") - /** 椤圭洰闃舵(0鍌ㄥ瑙勫垝闃舵, 1椤圭洰鍓嶆湡闃舵, 2瀹炴柦闃舵, 3绔e伐鎶曠敤闃舵) */ - private String projectPhase; +// @TableField("project_phase") +// /** 椤圭洰闃舵(0鍌ㄥ瑙勫垝闃舵, 1椤圭洰鍓嶆湡闃舵, 2瀹炴柦闃舵, 3绔e伐鎶曠敤闃舵) */ +// private String projectPhase; @TableField("tag") /** 鏍囩 */ diff --git a/business/src/main/java/com/ycl/domain/excel/ProjectExcelTemplate.java b/business/src/main/java/com/ycl/domain/excel/ProjectExcelTemplate.java new file mode 100644 index 0000000..58228b0 --- /dev/null +++ b/business/src/main/java/com/ycl/domain/excel/ProjectExcelTemplate.java @@ -0,0 +1,655 @@ +package com.ycl.domain.excel; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 瀵煎嚭妯℃澘绫� + * + * @Author: ljx + * @CreateTime: 2024-10-18 10:19 + */ + +@Data +public class ProjectExcelTemplate { + private static final long serialVersionUID = 1L; + + /* 椤圭洰绠$悊鍩虹淇℃伅琛� */ + + /** + * 椤圭洰鍚嶇О + */ + @ExcelProperty(value = "椤圭洰鍚嶇О") + private String projectName; + + /** + * 椤圭洰浠g爜 + */ + @ExcelProperty(value = "椤圭洰浠g爜") + private String projectCode; + + /** + * 椤圭洰绫诲瀷 + */ + @ExcelProperty(value = "椤圭洰绫诲瀷") + private String projectType; + + /** + * 椤圭洰鐘舵�� + */ + @ExcelProperty(value = "椤圭洰鐘舵��") + private String projectStatus; + + /** + * 璧勯噾绫诲瀷 + */ + @ExcelProperty(value = "璧勯噾绫诲瀷") + private String fundType; + + /** + * 鎶曡祫绫诲埆 + */ + @ExcelProperty(value = "鎶曡祫绫诲埆") + private String investType; + + /** + * 閲嶇偣鍒嗙被 + */ + @ExcelProperty(value = "閲嶇偣鍒嗙被") + private String importanceType; + + /** + * 椤圭洰闃舵 + */ + @ExcelProperty(value = "椤圭洰闃舵") + private String projectPhase; + + /** + * 鏍囩 + */ + @ExcelProperty(value = "鏍囩") + private String tag; + + /** + * 涓荤閮ㄩ棬 + */ + @ExcelProperty(value = "涓荤閮ㄩ棬") + private String competentDepartment; + + /** + * 椤圭洰褰掑睘鍦� + */ + @ExcelProperty(value = "椤圭洰褰掑睘鍦�") + private String projectLocation; + + /** + * 缁忓害 + */ + @ExcelProperty(value = "缁忓害") + private String longitude; + + /** + * 绾害 + */ + @ExcelProperty(value = "绾害") + private String latitude; + + /** + * 绠$悊褰掑彛 + */ + @ExcelProperty(value = "绠$悊褰掑彛") + private String managementCentralization; + + /** + * 椤圭洰鐢虫姤闃舵 + */ + @ExcelProperty(value = "椤圭洰鐢虫姤闃舵") + private String projectApplicationPhase; + + /** + * 椤圭洰瀹℃壒绫诲瀷 + */ + @ExcelProperty(value = "椤圭洰瀹℃壒绫诲瀷") + private String projectApprovalType; + + /** + * 鎶曡祫鐩綍 + */ + @ExcelProperty(value = "鎶曡祫鐩綍") + private String investmentCatalogue; + + /** + * 瀹℃壒璁″垝涔� + */ + @ExcelProperty(value = "瀹℃壒璁″垝涔︼紙闄勪欢鍚嶏級") + private String approvalPlan; + + /** + * 鏄惁绔嬮」 + */ + @ExcelProperty(value = "鏄惁绔嬮」") + private String isSetProject; + + /** + * 鎴愮珛鏃堕棿 + */ + @ExcelProperty(value = "鎴愮珛鏃堕棿") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date setTime; + + /** + * 璧嬬爜鐘舵�� + */ + @ExcelProperty(value = "璧嬬爜鐘舵��") + private String assignmentStatus; + + /** + * 琛屾斂鍖哄垝 + */ + @ExcelProperty(value = "琛屾斂鍖哄垝") + private String area; + + /** + * 涓爣鏃堕棿 + */ + @ExcelProperty(value = "涓爣鏃堕棿") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date winTime; + + /** + * 涓爣鍗曚綅 + */ + @ExcelProperty(value = "涓爣鍗曚綅") + private String winUnit; + + /** + * 涓爣閲戦 + */ + @ExcelProperty(value = "涓爣閲戦") + private String winAmount; + + /** + * 璇︾粏鍦板潃 + */ + @ExcelProperty(value = "璇︾粏鍦板潃") + private String address; + + /** + * 寤鸿鍐呭 + */ + @ExcelProperty(value = "寤鸿鍐呭") + private String content; + + /** + * 鑱旂郴鏂瑰紡 + */ + @ExcelProperty(value = "鑱旂郴鏂瑰紡") + private String contact; + + /** + * 椤圭洰涓氫富鍗曚綅 + */ + @ExcelProperty(value = "椤圭洰涓氫富鍗曚綅") + private String projectOwnerUnit; + + /** + * 璁″垝寮�宸ユ椂闂� + */ + @ExcelProperty(value = "璁″垝寮�宸ユ椂闂�") + private Date planStartTime; + + /** + * 璁″垝绔e伐鏃堕棿 + */ + @ExcelProperty(value = "璁″垝绔e伐鏃堕棿") + private Date planCompleteTime; + + /** + * 椤圭洰鑱旂郴浜� + */ + @ExcelProperty(value = "椤圭洰鑱旂郴浜�") + private String projectContactPerson; + + /** + * 鏈勾璁″垝鎶曡祫 + */ + @ExcelProperty(value = "鏈勾璁″垝鎶曡祫") + private BigDecimal yearInvestAmount; + + + /* 鎶曡祫椤圭洰鍩虹淇℃伅琛� */ + + /** + * 寤鸿鍦扮偣鏄惁璺ㄥ煙 + */ + @ExcelProperty(value = "寤鸿鍦扮偣鏄惁璺ㄥ煙") + private String beCrossRegion; + + /** + * 椤圭洰寤鸿鍦扮偣 + */ + @ExcelProperty(value = "寤鸿鍦扮偣") + private String constructionLocation; + + + /** + * 寤鸿璇︾粏鍦板潃 + */ + @ExcelProperty(value = "寤鸿璇︾粏鍦板潃") + private String detailedAddress; + + /** + * 鏄惁鏄ˉ鐮侀」鐩� + */ + @ExcelProperty(value = "鏄惁鏄ˉ鐮侀」鐩�") + private String beCompensationProject; + + /** + * 琛ョ爜鍘熷洜 + */ + @ExcelProperty(value = "琛ョ爜鍘熷洜") + private String compensationReason; + + /** + * 璁″垝寮�宸ユ椂闂� + */ + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ExcelProperty(value = "璁″垝寮�宸ユ椂闂�") + private Date plannedStartDate; + + /** + * 鎷熷缓鎴愭椂闂� + */ + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ExcelProperty(value = "鎷熷缓鎴愭椂闂�") + private Date expectedCompletionDate; + + /** + * 鍥芥爣琛屼笟鍒嗙被 + */ + @ExcelProperty(value = "鍥芥爣琛屼笟鍒嗙被") + private String nationalIndustryClassification; + + /** + * 鎵�灞炶涓氬垎绫� + */ + @ExcelProperty(value = "鎵�灞炶涓氬垎绫�") + private String industryClassification; + + /** + * 椤圭洰寤鸿鎬ц川 + */ + @ExcelProperty(value = "椤圭洰寤鸿鎬ц川") + private String projectNature; + + /** + * 椤圭洰灞炴�� + */ + @ExcelProperty(value = "椤圭洰灞炴��") + private String projectAttribute; + + /** + * 鏄惁浣跨敤鍦熷湴 + */ + @ExcelProperty(value = "鏄惁浣跨敤鍦熷湴") + private String useEarth; + + /** + * 涓昏寤鸿鍐呭鍙婅妯� + */ + @ExcelProperty(value = "涓昏寤鸿鍐呭鍙婅妯�") + private String contentScale; + + /** + * 寤虹骞冲彴浠g爜 + */ + @ExcelProperty(value = "寤虹骞冲彴浠g爜") + private String code; + + + /* 椤圭洰鎶曡祫鍙婅祫閲戞潵婧� */ + + /** + * 椤圭洰鎬绘姇璧勯 + */ + @ExcelProperty(value = "椤圭洰鎬绘姇璧勯") + private String totalInvestment; + + /** + * 椤圭洰鏈噾 + */ + @ExcelProperty(value = "椤圭洰鏈噾") + private String principal; + + /** + * 鏀垮簻鎶曡祫鎬婚 + */ + @ExcelProperty(value = "鏀垮簻鎶曡祫鎬婚") + private String governmentInvestmentTotal; + + /** + * 涓ぎ鎶曡祫鎬婚 + */ + @ExcelProperty(value = "涓ぎ鎶曡祫鎬婚") + private String centralInvestmentTotal; + + /** + * 涓ぎ棰勭畻鎶曡祫 + */ + @ExcelProperty(value = "涓ぎ棰勭畻鎶曡祫") + private String centralBudgetInvestment; + + /** + * 涓ぎ璐㈡斂 + */ + @ExcelProperty(value = "涓ぎ璐㈡斂") + private String centralFiscalInvestment; + + /** + * 涓ぎ涓撻」鍊哄埜绛归泦鐨勪笓椤瑰缓璁捐祫閲� + */ + @ExcelProperty(value = "涓ぎ涓撻」鍊哄埜绛归泦鐨勪笓椤瑰缓璁捐祫閲�") + private String centralSpecialBondInvestment; + + /** + * 涓ぎ涓撻」寤鸿鍩洪噾 + */ + @ExcelProperty(value = "涓ぎ涓撻」寤鸿鍩洪噾") + private String centralSpecialFundInvestment; + + /** + * 鐪佺骇鎶曡祫鎬婚 + */ + @ExcelProperty(value = "鐪佺骇鎶曡祫鎬婚") + private String provincialInvestmentTotal; + + /** + * 鐪侀绠楀唴鎶曡祫 + */ + @ExcelProperty(value = "鐪侀绠楀唴鎶曡祫") + private String provincialBudgetInvestment; + + /** + * 鐪佽储鏀挎�у缓璁炬姇璧� + */ + @ExcelProperty(value = "鐪佽储鏀挎�у缓璁炬姇璧�") + private String provincialFiscalInvestment; + + /** + * 鐪佷笓椤瑰缓璁捐祫閲� + */ + @ExcelProperty(value = "鐪佷笓椤瑰缓璁捐祫閲�") + private String provincialSpecialFundInvestment; + + /** + * 甯傦紙宸烇級鎶曡祫鎬婚 + */ + @ExcelProperty(value = "甯傦紙宸烇級鎶曡祫鎬婚") + private String cityInvestmentTotal; + + /** + * 甯傦紙宸烇級棰勭畻鍐呮姇璧� + */ + @ExcelProperty(value = "甯傦紙宸烇級棰勭畻鍐呮姇璧�") + private String cityBudgetInvestment; + + /** + * 甯傦紙宸烇級璐㈡斂鎬ф姇璧� + */ + @ExcelProperty(value = "甯傦紙宸烇級璐㈡斂鎬ф姇璧�") + private String cityFiscalInvestment; + + /** + * 甯傦紙宸烇級涓撻」璧勯噾 + */ + @ExcelProperty(value = "甯傦紙宸烇級涓撻」璧勯噾") + private String citySpecialFundInvestment; + + /** + * 鍘匡紙甯傘�佸尯锛夋姇璧勬�婚 + */ + @ExcelProperty(value = "鍘匡紙甯傘�佸尯锛夋姇璧勬�婚") + private String countyInvestmentTotal; + + /** + * 鍘匡紙甯傘�佸尯锛夐绠楀唴鎶曡祫 + */ + @ExcelProperty(value = "鍘匡紙甯傘�佸尯锛夐绠楀唴鎶曡祫") + private String countyBudgetInvestment; + + /** + * 鍘匡紙甯傘�佸尯锛夎储鏀挎�у缓璁捐祫閲� + */ + @ExcelProperty(value = "鍘匡紙甯傘�佸尯锛夎储鏀挎�у缓璁捐祫閲�") + private String countyFiscalInvestment; + + /** + * 鍘匡紙甯傘�佸尯锛変笓椤硅祫閲� + */ + @ExcelProperty(value = "鍘匡紙甯傘�佸尯锛変笓椤硅祫閲�") + private String countySpecialFundInvestment; + + /** + * 鍥藉唴璐锋鎬婚 + */ + @ExcelProperty(value = "鍥藉唴璐锋鎬婚") + private String domesticLoanTotal; + + /** + * 閾惰璐锋 + */ + @ExcelProperty(value = "閾惰璐锋") + private String bankLoan; + + /** + * 澶栧晢鎶曡祫鎬婚 + */ + @ExcelProperty(value = "澶栧晢鎶曡祫鎬婚") + private String foreignInvestmentTotal; + + /** + * 浼佷笟鑷鎬婚 + */ + @ExcelProperty(value = "浼佷笟鑷鎬婚") + private String enterpriseSelfRaisedTotal; + + /** + * 鍏朵粬鎶曡祫鎬婚 + */ + @ExcelProperty(value = "鍏朵粬鎶曡祫鎬婚") + private String otherInvestmentTotal; + + + /* 椤圭洰锛堟硶浜猴級鍗曚綅鐧昏淇℃伅琛� */ + +// /** +// * 椤圭洰鎬绘姇璧勯(鏍规嵁鍓嶉潰鐨勬暟鎹~鍏�) +// */ +// private BigDecimal totalInvestment; + + /** + * 椤圭洰鍗曚綅 + */ + @ExcelProperty(value = "椤圭洰鍗曚綅") + private String projectUnit; + + /** + * 椤圭洰鍗曚綅绫诲瀷 + */ + @ExcelProperty(value = "椤圭洰鍗曚綅绫诲瀷") + private String projectUnitType; + + /** + * 鐧昏娉ㄥ唽绫诲瀷 + */ + @ExcelProperty(value = "鐧昏娉ㄥ唽绫诲瀷") + private String registrationType; + + /** + * 鎺ц偂鎯呭喌 + */ + @ExcelProperty(value = "鎺ц偂鎯呭喌") + private String holdingSituation; + + /** + * 璇佺収绫诲瀷 + */ + @ExcelProperty(value = "璇佺収绫诲瀷") + private String certificateType; + + /** + * 璇佺収鍙风爜 + */ + @ExcelProperty(value = "璇佺収鍙风爜") + private String certificateNumber; + + /** + * 娉ㄥ唽鍦板潃 + */ + @ExcelProperty(value = "娉ㄥ唽鍦板潃") + private String registeredAddress; + + /** + * 娉ㄥ唽璧勯噾 + */ + @ExcelProperty(value = "娉ㄥ唽璧勯噾") + private BigDecimal registeredCapital; + + /** + * 娉曚汉浠h〃 + */ + @ExcelProperty(value = "娉曚汉浠h〃") + private String legal_representative; + + /** + * 鍥哄畾鐢佃瘽 + */ + @ExcelProperty(value = "鍥哄畾鐢佃瘽") + private String fixedPhone; + + /** + * 娉曚汉韬唤璇� + */ + @ExcelProperty(value = "娉曚汉韬唤璇�") + private String legalPersonIdcard; + +// /** +// * 椤圭洰鑱旂郴浜猴紙鏍规嵁鍓嶉潰鐨勬暟鎹~鍏咃級 +// */ +// private String projectContactPerson; + + /** + * 绉诲姩鐢佃瘽 + */ + @ExcelProperty(value = "绉诲姩鐢佃瘽") + private String phone; + + /** + * 鑱旂郴浜鸿韩浠借瘉 + */ + @ExcelProperty(value = "鑱旂郴浜鸿韩浠借瘉") + private String contactIdcard; + + /** + * 寰俊鍙� + */ + @ExcelProperty(value = "寰俊鍙�") + private String wechat; + + /** + * 鑱旂郴浜洪�氳鍦板潃 + */ + @ExcelProperty(value = "鑱旂郴浜洪�氳鍦板潃") + private String contactAddress; + + /** + * 閭斂缂栫爜 + */ + @ExcelProperty(value = "閭斂缂栫爜") + private String postCode; + + /** + * 鐢靛瓙閭 + */ + @ExcelProperty(value = "鐢靛瓙閭") + private String email; + + /* 鎶曡祫椤圭洰浜т笟鏀跨瓥绗﹀悎鎯呭喌琛� */ + + + /** + * 绗﹀悎浜т笟鏀跨瓥闄勪欢 + */ + @ExcelProperty(value = "绗﹀悎浜т笟鏀跨瓥(闄勪欢鍚�)") + private String policyComplianceAttachment; + + /** + * 鏄惁灞炰簬銆婁骇涓氱粨鏋勮皟鏁存寚瀵肩洰褰曘�嬩笅鐨勯」鐩� + */ + @ExcelProperty(value = "灞炰簬銆婁骇涓氱粨鏋勮皟鏁存寚瀵肩洰褰曘�嬩笅鐨勯」鐩�") + private String belongsToIndustryAdjustmentDirectory; + + /** + * 鏄惁灞炰簬鏈垪鍏ャ�婁骇涓氱粨鏋勮皟鏁存寚瀵肩洰褰曘�嬬殑鍏佽绫婚」鐩� + */ + @ExcelProperty(value = "灞炰簬鏈垪鍏ャ�婁骇涓氱粨鏋勮皟鏁存寚瀵肩洰褰曘�嬬殑鍏佽绫婚」鐩�") + private String belongsToAllowedProjects; + + /** + * 鏄惁灞炰簬銆婅タ閮ㄥ湴鍖洪紦鍔辩被浜т笟鐩綍銆嬬殑椤圭洰 + */ + @ExcelProperty(value = "灞炰簬銆婅タ閮ㄥ湴鍖洪紦鍔辩被浜т笟鐩綍銆嬬殑椤圭洰") + private String belongsToWesternEncouragedDirectory; + + /** + * 鏄惁涓嶅睘浜庝骇涓氭斂绛栫姝㈡姇璧勫缓璁炬垨瀹炶鏍稿噯銆佸鎵圭鐞嗙殑椤圭洰 + */ + @ExcelProperty(value = "涓嶅睘浜庝骇涓氭斂绛栫姝㈡姇璧勫缓璁炬垨瀹炶鏍稿噯銆佸鎵圭鐞嗙殑椤圭洰") + private String notBannedOrControlledProject; + + /** + * 濉姤淇℃伅鏄惁鐪熷疄 + */ + @ExcelProperty(value = "濉姤淇℃伅鏄惁鐪熷疄") + private String informationIsTrue; + + /** + * 涓撻」瑙勫垝澶嶅悎鎯呭喌 + */ + @ExcelProperty(value = "涓撻」瑙勫垝澶嶅悎鎯呭喌") + private String specialPlanningCompliance; + + /** + * 椤圭洰鑳借�楁儏鍐� + */ + @ExcelProperty(value = "椤圭洰鑳借�楁儏鍐�") + private String energyConsumption; + + /** + * 椤圭洰骞寸患鍚堣兘婧愭秷璐归噺锛堟爣鍑嗙叅褰撻噺鍊硷級 + */ + @ExcelProperty(value = "椤圭洰骞寸患鍚堣兘婧愭秷璐归噺锛堟爣鍑嗙叅褰撻噺鍊硷級") + private BigDecimal annualEnergyConsumption; + + /** + * 椤圭洰骞寸數鍔涙秷鑰楅噺锛堟爣鍑嗙叅褰撻噺鍊硷級 + */ + @ExcelProperty(value = "椤圭洰骞寸數鍔涙秷鑰楅噺锛堟爣鍑嗙叅褰撻噺鍊硷級") + private BigDecimal annualElectricityConsumption; + + + /* 鐩稿叧鏂囦功 */ + @ExcelProperty(value = "鐩稿叧鏂囦功锛堥檮浠跺悕锛�") + private String documents; + + +} diff --git a/business/src/main/java/com/ycl/domain/query/ProjectInfoQuery.java b/business/src/main/java/com/ycl/domain/query/ProjectInfoQuery.java index 071663f..d3247c9 100644 --- a/business/src/main/java/com/ycl/domain/query/ProjectInfoQuery.java +++ b/business/src/main/java/com/ycl/domain/query/ProjectInfoQuery.java @@ -1,8 +1,12 @@ package com.ycl.domain.query; +import com.fasterxml.jackson.annotation.JsonFormat; import com.ycl.system.domain.base.AbsQuery; import io.swagger.annotations.ApiModel; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; /** * 椤圭洰绠$悊鍩虹淇℃伅琛ㄦ煡璇� @@ -13,5 +17,37 @@ @Data @ApiModel(value = "ProjectInfo鏌ヨ鍙傛暟", description = "椤圭洰绠$悊鍩虹淇℃伅琛ㄦ煡璇㈠弬鏁�") public class ProjectInfoQuery extends AbsQuery { + //椤圭洰绫诲埆 + private String projectCategory; + //椤圭洰鍚嶇О + private String projectName; + //椤圭洰浠g爜 + private String projectCode; + //椤圭洰绫诲瀷 + private String projectType; + //閲嶇偣鍒嗙被 + private String importanceType; + //椤圭洰鏍囩 + private String tag; + //椤圭洰鐘舵�� + private String projectStatus; + //椤圭洰鐮� + private String projectColorCode; + //鍏宠仈鐘舵�� + private String assignmentStatus; + //璧勯噾绫诲瀷 + private String fundType; + //椤圭洰闃舵 + private String projectPhase; + //鎶曡祫绫诲埆 + private String investType; + //琛屾斂鍖哄垝 + private String area; + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date projectStartTime; + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date projectEndTime; + //浠庢湁娌℃湁娴佺▼鍒ゆ柇鏄瓨鍌ㄨ繕鏄棭鏈� + private String reserveOrPrevious; } diff --git a/business/src/main/java/com/ycl/domain/vo/ProjectInfoVO.java b/business/src/main/java/com/ycl/domain/vo/ProjectInfoVO.java index ee49ea6..1f73b75 100644 --- a/business/src/main/java/com/ycl/domain/vo/ProjectInfoVO.java +++ b/business/src/main/java/com/ycl/domain/vo/ProjectInfoVO.java @@ -67,7 +67,7 @@ /** 涓荤閮ㄩ棬(瀵瑰簲瀹℃壒閮ㄩ棬id) */ @ApiModelProperty("涓荤閮ㄩ棬(瀵瑰簲瀹℃壒閮ㄩ棬id)") private List<Long> competentDepartmentList; - + private String competentDepartment; /** 琛屾斂鍖哄煙 */ @ApiModelProperty("琛屾斂鍖哄煙") private String area; @@ -75,7 +75,7 @@ /** 绠$悊褰掑彛 (0鍩烘湰寤鸿(鍙戞敼), 1鏇存柊鏀归��(缁忎俊), 2鍗曠函璐疆(鍙戞敼), 3淇℃伅鍖�(鍙戞敼), 4鍏朵粬鎶曡祫) */ @ApiModelProperty("绠$悊褰掑彛 (0鍩烘湰寤鸿(鍙戞敼), 1鏇存柊鏀归��(缁忎俊), 2鍗曠函璐疆(鍙戞敼), 3淇℃伅鍖�(鍙戞敼), 4鍏朵粬鎶曡祫)") private List<String> managementCentralizationList; - + private String managementCentralization; /** 椤圭洰瀹℃壒绫诲瀷 */ @ApiModelProperty("椤圭洰瀹℃壒绫诲瀷") private String projectApprovalType; @@ -159,6 +159,11 @@ @ApiModelProperty("鏂囦欢") private List<File> fileList; + private Long processId; + private ProjectInvestmentInfoVO projectInvestmentInfo; + private ProjectInvestmentFundingVO projectInvestmentFunding; + private ProjectUnitRegistrationInfoVO projectUnitRegistrationInfo; + private ProjectInvestmentPolicyComplianceVO projectInvestmentPolicyCompliance; public static ProjectInfoVO getVoByEntity(@NonNull ProjectInfo entity, ProjectInfoVO vo) { if(vo == null) { @@ -180,5 +185,20 @@ } return vo; } - + //杞崲瀛楃涓查泦鍚堝瓧娈� + public static void transform(@NonNull ProjectInfoVO vo) { + //涓荤閮ㄩ棬杞垚list + String competentDepartment = vo.getCompetentDepartment(); + if(!StringUtils.isBlank(competentDepartment)){ + List<Long> list = Arrays.stream(competentDepartment.split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + vo.setCompetentDepartmentList(list); + } + //绠$悊褰掑彛杞崲 + String managementCentralization = vo.getManagementCentralization(); + if(!StringUtils.isBlank(managementCentralization)){ + vo.setManagementCentralizationList(Arrays.asList(managementCentralization.split(","))); + } + } } diff --git a/business/src/main/java/com/ycl/domain/vo/ProjectVO.java b/business/src/main/java/com/ycl/domain/vo/ProjectVO.java new file mode 100644 index 0000000..119abd9 --- /dev/null +++ b/business/src/main/java/com/ycl/domain/vo/ProjectVO.java @@ -0,0 +1,17 @@ +package com.ycl.domain.vo; + +import com.ycl.domain.excel.ProjectExcelTemplate; +import lombok.Data; + +import java.util.List; + +@Data +public class ProjectVO extends ProjectExcelTemplate { + private Long id; + /** 鐘舵�佺爜 */ + private String projectColorCode; + private List<Long> competentDepartmentList; + private List<String> managementCentralizationList; + + private Long processId; +} diff --git a/business/src/main/java/com/ycl/service/impl/ProjectInfoServiceImpl.java b/business/src/main/java/com/ycl/service/impl/ProjectInfoServiceImpl.java index 05a25e8..3adc8f2 100644 --- a/business/src/main/java/com/ycl/service/impl/ProjectInfoServiceImpl.java +++ b/business/src/main/java/com/ycl/service/impl/ProjectInfoServiceImpl.java @@ -1,10 +1,14 @@ package com.ycl.service.impl; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ycl.common.base.Result; import com.ycl.common.enums.business.FileTypeEnum; +import com.ycl.common.enums.business.ProjectCategoryEnum; +import com.ycl.common.utils.CopyUtils; +import com.ycl.common.utils.DateUtils; import com.ycl.common.utils.SecurityUtils; import com.ycl.domain.entity.File; import com.ycl.domain.entity.ProjectInfo; @@ -39,6 +43,7 @@ private final ProjectInfoMapper projectInfoMapper; private final FileService fileService; private final FileMapper fileMapper; + /** * 娣诲姞 * @@ -56,7 +61,7 @@ baseMapper.insert(entity); //娣诲姞鏂囦欢 List<File> fileList = form.getFileList(); - fileList.forEach(item->{ + fileList.forEach(item -> { item.setBusId(entity.getId()); item.setType(FileTypeEnum.PROJECT_INFO); }); @@ -76,20 +81,21 @@ ProjectInfo entity = baseMapper.selectById(form.getId()); // 涓虹┖鎶汭llegalArgumentException锛屽仛鍏ㄥ眬寮傚父澶勭悊 Assert.notNull(entity, "璁板綍涓嶅瓨鍦�"); - ProjectInfoForm.getEntityByForm(form,entity); + ProjectInfoForm.getEntityByForm(form, entity); Long userId = SecurityUtils.getUserId(); entity.setUpdateBy(userId); //鏇存柊椤圭洰淇℃伅 baseMapper.updateById(entity); List<File> fileList = form.getFileList(); - fileList.forEach(item->{ + fileList.forEach(item -> { + item.setId(null); item.setBusId(entity.getId()); item.setType(FileTypeEnum.PROJECT_INFO); }); //鍒犻櫎鍘熸湁鏂囦欢 QueryWrapper<File> fileQueryWrapper = new QueryWrapper<>(); - fileQueryWrapper.eq("type",FileTypeEnum.PROJECT_INFO.getType()); - fileQueryWrapper.eq("bus_id",entity.getId()); + fileQueryWrapper.eq("type", FileTypeEnum.PROJECT_INFO.getType()); + fileQueryWrapper.eq("bus_id", entity.getId()); fileMapper.delete(fileQueryWrapper); //鏇挎崲鎴愮幇鏈� fileService.saveBatch(fileList); @@ -130,17 +136,54 @@ */ @Override public Result page(ProjectInfoQuery query) { - IPage<ProjectInfo> page = PageUtil.getPage(query, ProjectInfo.class); + if (query.getProjectStartTime() != null) { + query.setProjectStartTime(DateUtils.getDayStart(query.getProjectStartTime())); + } + if (query.getProjectEndTime() != null) { + query.setProjectEndTime(DateUtils.getDayEnd(query.getProjectEndTime())); + } + String projectCategory = query.getProjectCategory(); + if (ProjectCategoryEnum.RESERVE.getType().equals(projectCategory)) { + query.setProjectStatus(ProjectCategoryEnum.RESERVE.getStatus()); + query.setReserveOrPrevious(ProjectCategoryEnum.RESERVE.getCode()); + } else if (ProjectCategoryEnum.PREVIOUS.getType().equals(projectCategory)) { + query.setProjectStatus(ProjectCategoryEnum.PREVIOUS.getStatus()); + query.setReserveOrPrevious(ProjectCategoryEnum.PREVIOUS.getCode()); + } else if (ProjectCategoryEnum.FINISH.getType().equals(projectCategory)) { + query.setProjectStatus(ProjectCategoryEnum.FINISH.getStatus()); + } else if (ProjectCategoryEnum.EXCEPTION.getType().equals(projectCategory)) { + //TODO + //鍏堟煡鍑哄紓甯告祦绋嬫垨鑰呭紓甯歌繘搴︽垨鑰呭紓甯歌鍒掔殑projectId鍜屽紓甯哥绫� + //閫氳繃projectId鏌ュ嚭椤圭洰鏁版嵁 + //琛ュ厖鐩稿簲鐨勫紓甯告暟鎹紙寮傚父绉嶇被銆佸紓甯告祦绋嬭妭鐐圭瓑锛� + List<ProjectVO> list = new ArrayList<>(); + return Result.ok().data(list).total(0); + } + + IPage<ProjectInfoVO> page = PageUtil.getPage(query, ProjectInfoVO.class); baseMapper.getPage(page, query); - List<ProjectInfo> records = page.getRecords(); - List<ProjectInfoVO> list = records.stream() - .map(entity -> { - ProjectInfoVO vo = ProjectInfoVO.getVoByEntity(entity, null); + List<ProjectInfoVO> records = page.getRecords(); + List<ProjectVO> list = new ArrayList<>(); + records.forEach(vo -> { + ProjectInfoVO.transform(vo); vo.setProjectColorCode("green"); - return vo; - }) - .collect(Collectors.toList()); + ProjectVO projectVO = new ProjectVO(); + copyToProjectVO(vo,projectVO); + //缈昏瘧椤圭洰闃舵 + String phase = ProjectCategoryEnum.getPhaseByProjectStatus(projectVO.getProjectStatus(), projectVO.getProcessId() != null); + projectVO.setProjectPhase(phase); + list.add(projectVO); + }); return Result.ok().data(list).total(page.getTotal()); + } + + private void copyToProjectVO(ProjectInfoVO vo,ProjectVO projectVO) { + //蹇界暐null鍊肩殑澶嶅埗 + CopyUtils.copyNoNullProperties(vo, projectVO); + if(vo.getProjectInvestmentFunding()!=null) CopyUtils.copyNoNullProperties(vo.getProjectInvestmentFunding(),projectVO); + if(vo.getProjectInvestmentInfo()!=null) CopyUtils.copyNoNullProperties(vo.getProjectInvestmentInfo(),projectVO); + if(vo.getProjectUnitRegistrationInfo()!=null) CopyUtils.copyNoNullProperties(vo.getProjectUnitRegistrationInfo(),projectVO); + if(vo.getProjectInvestmentPolicyCompliance()!=null) CopyUtils.copyNoNullProperties(vo.getProjectInvestmentPolicyCompliance(),projectVO); } /** @@ -155,8 +198,8 @@ Assert.notNull(entity, "璁板綍涓嶅瓨鍦�"); ProjectInfoVO vo = ProjectInfoVO.getVoByEntity(entity, null); QueryWrapper<File> fileQueryWrapper = new QueryWrapper<>(); - fileQueryWrapper.eq("type",FileTypeEnum.PROJECT_INFO.getType()); - fileQueryWrapper.eq("bus_id",vo.getId()); + fileQueryWrapper.eq("type", FileTypeEnum.PROJECT_INFO.getType()); + fileQueryWrapper.eq("bus_id", vo.getId()); List<File> files = fileMapper.selectList(fileQueryWrapper); vo.setFileList(files); return Result.ok().data(vo); @@ -213,8 +256,8 @@ public Result docDetail(Integer id) { DocumentInfoForm documentInfoForm = new DocumentInfoForm(); QueryWrapper<File> fileQueryWrapper = new QueryWrapper<>(); - fileQueryWrapper.eq("type",FileTypeEnum.DOCUMENT_INFO.getType()); - fileQueryWrapper.eq("bus_id",id); + fileQueryWrapper.eq("type", FileTypeEnum.DOCUMENT_INFO.getType()); + fileQueryWrapper.eq("bus_id", id); List<File> files = fileMapper.selectList(fileQueryWrapper); documentInfoForm.setFileList(files); return Result.ok().data(documentInfoForm); @@ -223,14 +266,15 @@ @Override public Result addDoc(DocumentInfoForm form) { List<File> fileList = form.getFileList(); - fileList.forEach(item->{ + fileList.forEach(item -> { + item.setId(null); item.setBusId(form.getProjectId()); item.setType(FileTypeEnum.DOCUMENT_INFO); }); //鍒犻櫎鍘熸湁鏂囦欢 QueryWrapper<File> fileQueryWrapper = new QueryWrapper<>(); - fileQueryWrapper.eq("type",FileTypeEnum.DOCUMENT_INFO.getType()); - fileQueryWrapper.eq("bus_id",form.getProjectId()); + fileQueryWrapper.eq("type", FileTypeEnum.DOCUMENT_INFO.getType()); + fileQueryWrapper.eq("bus_id", form.getProjectId()); fileMapper.delete(fileQueryWrapper); //鏇挎崲鎴愮幇鏈� fileService.saveBatch(fileList); diff --git a/business/src/main/java/com/ycl/service/impl/ProjectInvestmentPolicyComplianceServiceImpl.java b/business/src/main/java/com/ycl/service/impl/ProjectInvestmentPolicyComplianceServiceImpl.java index ddf8c91..0d7ef45 100644 --- a/business/src/main/java/com/ycl/service/impl/ProjectInvestmentPolicyComplianceServiceImpl.java +++ b/business/src/main/java/com/ycl/service/impl/ProjectInvestmentPolicyComplianceServiceImpl.java @@ -56,6 +56,7 @@ //娣诲姞鏂囦欢 List<File> fileList = form.getFileList(); fileList.forEach(item->{ + item.setId(null); item.setBusId(entity.getId()); item.setType(FileTypeEnum.INVEST_POLICY); }); @@ -80,6 +81,7 @@ baseMapper.updateById(entity); List<File> fileList = form.getFileList(); fileList.forEach(item->{ + item.setId(null); item.setBusId(entity.getId()); item.setType(FileTypeEnum.INVEST_POLICY); }); diff --git a/business/src/main/resources/mapper/ProjectInfoMapper.xml b/business/src/main/resources/mapper/ProjectInfoMapper.xml index 4beeb90..0da2550 100644 --- a/business/src/main/resources/mapper/ProjectInfoMapper.xml +++ b/business/src/main/resources/mapper/ProjectInfoMapper.xml @@ -3,44 +3,15 @@ <mapper namespace="com.ycl.mapper.ProjectInfoMapper"> <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 --> - <resultMap id="BaseResultMap" type="com.ycl.domain.entity.ProjectInfo"> - <id column="id" property="id"/> - <result column="project_name" property="projectName" /> - <result column="project_code" property="projectCode" /> - <result column="content" property="content" /> - <result column="project_type" property="projectType" /> - <result column="project_status" property="projectStatus" /> - <result column="fund_type" property="fundType" /> - <result column="invest_type" property="investType" /> - <result column="project_phase" property="projectPhase" /> - <result column="tag" property="tag" /> - <result column="competent_department" property="competentDepartment" /> - <result column="area" property="area" /> - <result column="management_centralization" property="managementCentralization" /> - <result column="project_approval_type" property="projectApprovalType" /> - <result column="importance_type" property="importanceType" /> - <result column="year" property="year" /> - <result column="year_invest_amount" property="yearInvestAmount" /> - <result column="create_project_time" property="createProjectTime" /> - <result column="plan_start_time" property="planStartTime" /> - <result column="plan_complete_time" property="planCompleteTime" /> - <result column="win_unit" property="winUnit" /> - <result column="win_amount" property="winAmount" /> - <result column="win_time" property="winTime" /> - <result column="project_address" property="projectAddress" /> - <result column="longitude" property="longitude" /> - <result column="latitude" property="latitude" /> - <result column="project_owner_unit" property="projectOwnerUnit" /> - <result column="project_contact_person" property="projectContactPerson" /> - <result column="contact" property="contact" /> - <result column="gmt_create" property="gmtCreate" /> - <result column="gmt_update" property="gmtUpdate" /> - <result column="update_by" property="updateBy" /> - <result column="create_by" property="createBy" /> + <resultMap id="resultMap" type="com.ycl.domain.vo.ProjectInfoVO" autoMapping="true"> + <association property="projectInvestmentInfo" javaType="com.ycl.domain.vo.ProjectInvestmentInfoVO" autoMapping="true" columnPrefix="TPII_"/> + <association property="projectInvestmentFunding" javaType="com.ycl.domain.vo.ProjectInvestmentFundingVO" autoMapping="true" columnPrefix="TPIF_"/> + <association property="projectUnitRegistrationInfo" javaType="com.ycl.domain.vo.ProjectUnitRegistrationInfoVO" autoMapping="true" columnPrefix="TPURI_"/> + <association property="projectInvestmentPolicyCompliance" javaType="com.ycl.domain.vo.ProjectInvestmentPolicyComplianceVO" autoMapping="true" columnPrefix="TPIPC_"/> </resultMap> - <select id="getById" resultMap="BaseResultMap"> + <select id="getById" resultType="com.ycl.domain.entity.ProjectInfo"> SELECT TPI.project_name, TPI.project_code, @@ -82,45 +53,104 @@ </select> - <select id="getPage" resultMap="BaseResultMap"> + <select id="getPage" resultMap="resultMap"> SELECT - TPI.project_name, - TPI.project_code, - TPI.content, - TPI.project_type, - TPI.project_status, - TPI.fund_type, - TPI.invest_type, - TPI.project_phase, - TPI.tag, - TPI.competent_department, - TPI.area, - TPI.management_centralization, - TPI.project_approval_type, - TPI.importance_type, - TPI.year, - TPI.year_invest_amount, - TPI.create_project_time, - TPI.plan_start_time, - TPI.plan_complete_time, - TPI.win_unit, - TPI.win_amount, - TPI.win_time, - TPI.project_address, - TPI.longitude, - TPI.latitude, - TPI.project_owner_unit, - TPI.project_contact_person, - TPI.contact, - TPI.gmt_create, - TPI.gmt_update, - TPI.update_by, - TPI.create_by, - TPI.id + TPI.*,TPP.process_instance_id as processId, + TPIF.total_investment as TPIF_totalInvestment, + TPIF.principal as TPIF_principal,TPIF.government_investment_total as TPIF_government_investment_total,TPIF.central_investment_total as TPIF_central_investment_total, + TPIF.central_budget_investment as TPIF_central_budget_investment,TPIF.central_fiscal_investment as TPIF_central_fiscal_investment, + TPIF.central_special_bond_investment as TPIF_central_special_bond_investment,TPIF.central_special_fund_investment as TPIF_central_special_fund_investment, + TPIF.provincial_investment_total as TPIF_provincial_investment_total,TPIF.provincial_budget_investment as TPIF_provincial_budget_investment, + TPIF.provincial_fiscal_investment as TPIF_provincial_fiscal_investment,TPIF.provincial_special_fund_investment as TPIF_provincial_special_fund_investment, + TPIF.city_investment_total as TPIF_city_investment_total,TPIF.city_budget_investment as TPIF_city_budget_investment,TPIF.city_fiscal_investment as TPIF_city_fiscal_investment, + TPIF.city_special_fund_investment as TPIF_city_special_fund_investment,TPIF.county_investment_total as TPIF_county_investment_total,TPIF.county_budget_investment as TPIF_county_budget_investment, + TPIF.county_fiscal_investment as TPIF_county_fiscal_investment,TPIF.county_special_fund_investment as TPIF_county_special_fund_investment, + TPIF.domestic_loan_total as TPIF_domestic_loan_total,TPIF.bank_loan as TPIF_bank_loan,TPIF.foreign_investment_total as TPIF_foreign_investment_total, + TPIF.enterprise_self_raised_total as TPIF_enterprise_self_raised_total,TPIF.other_investment_total as TPIF_other_investment_total, + TPII.be_cross_region as TPII_be_cross_region,TPII.construction_location as TPII_construction_location, + TPII.detailed_address as TPII_detailed_address,TPII.be_compensation_project as TPII_be_compensation_project,TPII.compensation_reason as TPII_compensation_reason, + TPII.planned_start_date as TPII_planned_start_date,TPII.expected_completion_date as TPII_expected_completion_date, + TPII.national_industry_classification as TPII_national_industry_classification,TPII.industry_classification as TPII_industry_classification,TPII.project_nature as TPII_project_nature, + TPII.project_attribute as TPII_project_attribute,TPII.use_earth as TPII_use_earth,TPII.content_scale as TPII_content_scale,TPII.code as TPII_code, + TPIPC.belongs_to_industry_adjustment_directory as TPIPC_belongs_to_industry_adjustment_directory,TPIPC.belongs_to_western_encouraged_directory as TPIPC_belongs_to_western_encouraged_directory, + TPIPC.not_banned_or_controlled_project as TPIPC_not_banned_or_controlled_project,TPIPC.information_is_true as TPIPC_information_is_true, + TPIPC.special_planning_compliance as TPIPC_special_planning_compliance,TPIPC.annual_energy_consumption as TPIPC_annual_energy_consumption,TPIPC.annual_electricity_consumption as TPIPC_annual_electricity_consumption, + TPIPC.energy_check as TPIPC_energy_check,TPIPC.no_only_check_type as TPIPC_no_only_check_type,TPIPC.remarks as TPIPC_remarks, + TPURI.total_investment as TPURI_total_investment, + TPURI.project_unit as TPURI_project_unit, + TPURI.project_unit_type as TPURI_project_unit_type, + TPURI.registration_type as TPURI_registration_type, + TPURI.holding_situation as TPURI_holding_situation, + TPURI.certificate_type as TPURI_certificate_type, + TPURI.certificate_number as TPURI_certificate_number, + TPURI.registered_address as TPURI_registered_address, + TPURI.registered_capital as TPURI_registered_capital, + TPURI.legal_representative as TPURI_legal_representative, + TPURI.fixed_phone as TPURI_fixed_phone, + TPURI.legal_person_idcard as TPURI_legal_person_idcard, + TPURI.project_contact_person as TPURI_project_contact_person, + TPURI.phone as TPURI_phone, + TPURI.contact_idcard as TPURI_contact_idcard, + TPURI.wechat as TPURI_wechat, + TPURI.contact_address as TPURI_contact_address, + TPURI.post_code as TPURI_post_code, + TPURI.email as TPURI_email FROM t_project_info TPI - WHERE + LEFT JOIN t_project_investment_funding TPIF ON TPI.id = TPIF.project_id and TPIF.deleted = 0 + LEFT JOIN t_project_investment_info TPII ON TPI.id = TPII.project_id and TPII.deleted = 0 + LEFT JOIN t_project_investment_policy_compliance TPIPC ON TPI.id = TPIPC.project_id and TPIPC.deleted = 0 + LEFT JOIN t_project_unit_registration_info TPURI ON TPI.id = TPURI.project_id and TPURI.deleted = 0 + LEFT JOIN t_project_process TPP ON TPI.id = TPP.project_id and TPP.deleted = 0 + <where> TPI.deleted = 0 + <if test="query.projectName !=null and query.projectName!=''"> + and TPI.project_name like concat('%',#{query.projectName},'%') + </if> + <if test="query.projectCode !=null and query.projectCode!=''"> + and TPI.project_code like concat('%',#{query.projectCode},'%') + </if> + <if test="query.projectType !=null and query.projectType!=''"> + and TPI.project_type = #{query.projectType} + </if> + <if test="query.importanceType !=null and query.importanceType!=''"> + and TPI.importance_type = #{query.importanceType} + </if> + <if test="query.tag !=null and query.tag!=''"> + and TPI.tag like concat('%',#{query.tag},'%') + </if> + <if test="query.projectStatus !=null and query.projectStatus!=''"> + and TPI.project_status = #{query.projectStatus} + </if> + <if test="query.projectPhase !=null and query.projectPhase!=''"> + and TPI.project_phase = #{query.projectPhase} + </if> +<!-- <if test=" assignmentStatus !=null and assignmentStatus!=''">--> +<!-- and TPI.project_phase = #{projectPhase}--> +<!-- </if>--> + <if test="query.fundType !=null and query.fundType!=''"> + and TPI.fund_type = #{query.fundType} + </if> + <if test="query.projectPhase !=null and query.projectPhase!=''"> + and TPI.project_phase = #{query.projectPhase} + </if> + <if test="query.investType !=null and query.investType!=''"> + and TPI.invest_type = #{query.investType} + </if> + <if test="query.area !=null and query.area!=''"> + and TPI.area = #{query.area} + </if> + <if test="query.projectStartTime !=null and query.projectEndTime !=null"> + and TPI.create_project_time between #{query.projectStartTime} and #{query.projectEndTime} + </if> + <if test="query.reserveOrPrevious != null and query.reserveOrPrevious == 'reserve'"> + and TPP.process_instance_id is null + </if> + <if test="query.reserveOrPrevious != null and query.reserveOrPrevious == 'previous'"> + and TPP.process_instance_id is not null + </if> + </where> + order by TPI.gmt_create </select> </mapper> diff --git a/common/pom.xml b/common/pom.xml index 99d8e16..7ee7272 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -128,7 +128,16 @@ <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> </dependency> + <!-- easy excel --> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>easyexcel</artifactId> + </dependency> + <dependency> + <groupId>cn.hutool</groupId> + <artifactId>hutool-crypto</artifactId> + </dependency> </dependencies> </project> diff --git a/common/src/main/java/com/ycl/common/enums/business/ProjectCategoryEnum.java b/common/src/main/java/com/ycl/common/enums/business/ProjectCategoryEnum.java new file mode 100644 index 0000000..f152d46 --- /dev/null +++ b/common/src/main/java/com/ycl/common/enums/business/ProjectCategoryEnum.java @@ -0,0 +1,51 @@ +package com.ycl.common.enums.business; + +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ProjectCategoryEnum { + + RESERVE("1", "pendding", "鍌ㄥ椤圭洰","reserve","鍌ㄥ瑙勫垝闃舵"), + PREVIOUS("2", "pendding","鍓嶆湡椤圭洰","previous","椤圭洰鍓嶆湡闃舵"), + IMPLEMENT("3", "working,stop","瀹炴柦椤圭洰","implement","瀹炴柦闃舵"), + FINISH("4", "finish","绔e伐椤圭洰","finish","绔e伐鎶曠敤闃舵"), + EXCEPTION("5", "","寮傚父椤圭洰","exception",""); + + + private final String type; + private final String status; + private final String name; + private final String code; + private final String desc; + + //鍒ゆ柇浼犲叆鏁版嵁鏄惁瀛樺湪鍥涚椤圭洰鎺ㄨ繘鐘舵�� + public static boolean isValidType(String type) { + for (ProjectCategoryEnum status : ProjectCategoryEnum.values()) { + if (status.getDesc().equals(type) && ObjectUtil.notEqual(type,ProjectCategoryEnum.EXCEPTION.getName())) { + return true; + } + } + return false; + } + + /** + * 鑾峰彇椤圭洰闃舵 + * @param projectStatus + * @param hasProcess 鏄惁鍚姩娴佺▼ + * @return + */ + public static String getPhaseByProjectStatus(String projectStatus, boolean hasProcess) { + for (ProjectCategoryEnum projectCategoryEnum : ProjectCategoryEnum.values()) { + if (hasProcess && PREVIOUS.status.contains(projectStatus)) { + return PREVIOUS.desc; + } + if (projectCategoryEnum.status.contains(projectStatus)) { + return projectCategoryEnum.desc; + } + } + return null; + } +} diff --git a/common/src/main/java/com/ycl/common/utils/CopyUtils.java b/common/src/main/java/com/ycl/common/utils/CopyUtils.java new file mode 100644 index 0000000..5faafab --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/CopyUtils.java @@ -0,0 +1,48 @@ +package com.ycl.common.utils; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; + +import java.beans.PropertyDescriptor; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +/** + * 鑷畾涔夊鍒跺伐鍏风被 + */ +public class CopyUtils { + /** + * 鎵�鏈変负绌哄�肩殑灞炴�ч兘涓峜opy + * + * @param source + * @param target + */ + public static void copyNoNullProperties(Object source, Object target) { + BeanUtils.copyProperties(source, target, getNullField(source)); + } + + /** + * 鑾峰彇灞炴�т腑涓虹┖鐨勫瓧娈� + * + * @param target + * @return + */ + private static String[] getNullField(Object target) { + BeanWrapper beanWrapper = new BeanWrapperImpl(target); + PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors(); + Set<String> notNullFieldSet = new HashSet<>(); + if (propertyDescriptors.length > 0) { + for (PropertyDescriptor p : propertyDescriptors) { + String name = p.getName(); + Object value = beanWrapper.getPropertyValue(name); + if (Objects.isNull(value)) { + notNullFieldSet.add(name); + } + } + } + String[] notNullField = new String[notNullFieldSet.size()]; + return notNullFieldSet.toArray(notNullField); + } +} diff --git a/common/src/main/java/com/ycl/common/utils/DateUtils.java b/common/src/main/java/com/ycl/common/utils/DateUtils.java index b600bc6..43eaf68 100644 --- a/common/src/main/java/com/ycl/common/utils/DateUtils.java +++ b/common/src/main/java/com/ycl/common/utils/DateUtils.java @@ -1,6 +1,7 @@ package com.ycl.common.utils; import java.lang.management.ManagementFactory; +import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; @@ -9,7 +10,10 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Date; +import java.util.Objects; + import org.apache.commons.lang3.time.DateFormatUtils; +import org.springframework.lang.Nullable; /** * 鏃堕棿宸ュ叿绫� @@ -188,4 +192,35 @@ ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault()); return Date.from(zdt.toInstant()); } + + /** + * 鑾峰彇鏌愬ぉ鐨勫紑濮嬫椂闂� + * + * @param date + * @return 2023-01-01 00:00:00 + */ + + public static Date getDayStart(@Nullable Date date) { + if (Objects.isNull(date)) { + date = new Date(); + } + LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.of("GMT+8")); + LocalDateTime of = LocalDateTime.of(localDateTime.getYear(), localDateTime.getMonth(), localDateTime.getDayOfMonth(), 0, 0, 0); + return Timestamp.valueOf(of); + } + + /** + * 鑾峰彇鏌愬ぉ鐨勭粨鏉熸椂闂� + * + * @param date + * @return 2023-01-01 23:59:59 + */ + public static Date getDayEnd(@Nullable Date date) { + if (Objects.isNull(date)) { + date = new Date(); + } + LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); + LocalDateTime of = LocalDateTime.of(localDateTime.getYear(), localDateTime.getMonth(), localDateTime.getDayOfMonth(), 23, 59, 59); + return Timestamp.valueOf(of); + } } diff --git a/common/src/main/java/com/ycl/common/utils/excel/OutputExcelUtils.java b/common/src/main/java/com/ycl/common/utils/excel/OutputExcelUtils.java new file mode 100644 index 0000000..68d0bac --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/OutputExcelUtils.java @@ -0,0 +1,217 @@ +package com.ycl.common.utils.excel; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ZipUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; +import com.ycl.common.utils.excel.convert.ExcelBigNumberConvert; +import com.ycl.common.utils.excel.core.CellMergeStrategy; +import com.ycl.common.utils.excel.core.DropDownOptions; +import com.ycl.common.utils.excel.core.ExcelDownHandler; +import com.ycl.common.utils.file.FileUtils; +import org.apache.commons.codec.Charsets; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotNull; +import java.io.*; +import java.lang.reflect.Field; +import java.net.URLEncoder; +import java.nio.file.Files; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @Author: ljx + * @CreateTime: 2024-10-18 10:13 + */ + +public class OutputExcelUtils { + + /** + * 蹇界暐閮ㄥ垎瀵煎嚭瀛楁鏂规硶 + * @param response + * @param fileName 鏂囦欢鍚嶇О + * @param sheetName sheet鍚嶇О + * @param dataList 闇�瑕佸鍑虹殑鏁版嵁 + * @param clazz 绫� + * @param + * @param <T> + * @throws IOException + */ + public static <T> void export(HttpServletResponse response, String fileName, String sheetName, List<T> dataList, Class<T> clazz, List<String> fieldNames) throws IOException { + response.setContentType("application/zip"); + response.setCharacterEncoding(Charsets.UTF_8.name()); + fileName = URLEncoder.encode(fileName, Charsets.UTF_8); + response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".zip"); + Set<Integer> selectedIndexes = getSelectFields(fieldNames, clazz); + + //涓嬭浇妯℃澘 + downloadTemplate(response, sheetName, dataList, clazz, selectedIndexes); + + + // 涓存椂鍚戣祫婧愭枃浠跺す鍐� 鍚嶄负template鐨勬枃浠跺す +// ClassPathResource classPathResource = new ClassPathResource("/template/test.xls"); +// File file = classPathResource.getFile(); +// try(FileOutputStream fileOutputStream = new FileOutputStream(file,false)) { +// EasyExcel.write(fileOutputStream, clazz).sheet(sheetName).doWrite(dataList); +// } +// +// ClassPathResource classPathResource1 = new ClassPathResource("/template"); +// File zip = ZipUtil.zip(classPathResource1.getFile()); +// byte[] bytes; +// try (FileInputStream fileInputStream = new FileInputStream(zip)) { +// bytes = fileInputStream.readAllBytes(); +// } +// response.getOutputStream().write(bytes); + +// if (selectedIndexes.size() > 0) { +// EasyExcel.write(response.getOutputStream(), clazz).excludeColumnIndexes(selectedIndexes).sheet(sheetName).doWrite(dataList); +// } else { +// EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(dataList); +// } + } + + private synchronized static <T> void downloadTemplate(HttpServletResponse response, String sheetName, List<T> dataList, Class<T> clazz, Set<Integer> columnIndex) throws IOException { + + File tempDir = null; + try { + // 鍒涘缓涓存椂鐩綍 + tempDir = Files.createTempDirectory("temp").toFile(); + + File templateDir = new File(tempDir, "template"); + if (!templateDir.exists()) { + templateDir.mkdirs(); + } + + // 鍒涘缓 Excel 鏂囦欢 + File excelFile = new File(templateDir, "excel.xlsx"); + if (!excelFile.exists()) { + excelFile.createNewFile(); + } + + // 鍐欏叆 Excel 妯℃澘鏁版嵁 + try (FileOutputStream fileOutputStream = new FileOutputStream(excelFile, false)) { + EasyExcel.write(fileOutputStream, clazz).includeColumnIndexes(columnIndex).sheet(sheetName).doWrite(dataList); + } + + // 鍒涘缓闄勪欢鐩綍 + File attachmentDir = new File(templateDir, "attachment"); + if (!attachmentDir.exists()) { + attachmentDir.mkdirs(); + } + + // 鎵撳寘 ZIP 鏂囦欢 + File zipFile = ZipUtil.zip(templateDir); + byte[] zipBytes = Files.readAllBytes(zipFile.toPath()); + + // 灏� ZIP 鏂囦欢鍐欏叆鍝嶅簲 + try(ServletOutputStream outputStream = response.getOutputStream()) { + outputStream.write(zipBytes); + } + } finally { + deleteDirectoryOrFile(tempDir); + } + } + + private static void deleteDirectoryOrFile(File file) { + if (ObjectUtil.isNull(file)) { + return; + } + + if (file.isDirectory()) { + File[] files = file.listFiles(); + if (files != null) { + for (File f : files) { + deleteDirectoryOrFile(f); + } + } + } + file.delete(); + + } + + /** + * 瀵煎嚭妯℃澘 + * @param response + * @param fileName + * @param sheetName + * @param dataList + * @param clazz + * @param fieldNames + */ + public static <T> void exportTemplate(HttpServletResponse response,String fileName, String sheetName, List<T> dataList, Class<T> clazz, List<String> fieldNames) throws IOException { + Set<Integer> selectedIndexes = getSelectFields(fieldNames, clazz); + + resetResponse(fileName, response); + + exportExcel(dataList, sheetName, clazz, false, response.getOutputStream(), null, selectedIndexes); + } + + public static <T> @NotNull Set<Integer> getSelectFields(List<String> fieldNames, Class<T> clazz) { + Set<Integer> selectedIndexes = new HashSet<>(); + if (CollUtil.isNotEmpty(fieldNames)) { + // 鍙嶅皠鑾峰彇瀛楁灞炴�� + Field[] declaredFields = clazz.getDeclaredFields(); +// // 鍖归厤闇�瑕佸鍏ョ殑瀛楁 + for (int i = 0; i < declaredFields.length; i++) { + if (fieldNames.contains(declaredFields[i].getName())) { + // 鑾峰彇闇�瑕佸鍏ョ殑瀛楁涓嬫爣 + selectedIndexes.add(i); + } + } + } + return selectedIndexes; + + } + + /** + * 瀵煎嚭excel + * + * @param list 瀵煎嚭鏁版嵁闆嗗悎 + * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О + * @param clazz 瀹炰綋绫� + * @param merge 鏄惁鍚堝苟鍗曞厓鏍� + * @param os 杈撳嚭娴� + */ + public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, boolean merge, + OutputStream os, List<DropDownOptions> options, Set<Integer> selectedIndexes) { + ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz) + .autoCloseStream(false) + .includeColumnIndexes(selectedIndexes) + // 鑷姩閫傞厤 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 澶ф暟鍊艰嚜鍔ㄨ浆鎹� 闃叉澶辩湡 + .registerConverter(new ExcelBigNumberConvert()) + .sheet(sheetName); + if (merge) { + // 鍚堝苟澶勭悊鍣� + builder.registerWriteHandler(new CellMergeStrategy(list, true)); + } + // 娣诲姞涓嬫媺妗嗘搷浣� + builder.registerWriteHandler(new ExcelDownHandler(options)); + builder.doWrite(list); + } + + /** + * 閲嶇疆鍝嶅簲浣� + */ + private static void resetResponse(String sheetName, HttpServletResponse response) throws UnsupportedEncodingException { + String filename = encodingFilename(sheetName); + FileUtils.setAttachmentResponseHeader(response, filename); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"); + } + + /** + * 缂栫爜鏂囦欢鍚� + */ + public static String encodingFilename(String filename) { + return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx"; + } + + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/annotation/CellMerge.java b/common/src/main/java/com/ycl/common/utils/excel/annotation/CellMerge.java new file mode 100644 index 0000000..1b78f92 --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/annotation/CellMerge.java @@ -0,0 +1,29 @@ +package com.ycl.common.utils.excel.annotation; + +import com.ycl.common.utils.excel.core.CellMergeStrategy; + +import java.lang.annotation.*; + +/** + * excel 鍒楀崟鍏冩牸鍚堝苟(鍚堝苟鍒楃浉鍚岄」) + * <p> + * 闇�鎼厤 {@link CellMergeStrategy} 绛栫暐浣跨敤 + * + * @author Lion Li + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface CellMerge { + + /** + * col index + */ + int index() default -1; + + /** + * 鍚堝苟闇�瑕佷緷璧栫殑鍏朵粬瀛楁鍚嶇О + */ + String[] mergeBy() default {}; + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/annotation/ExcelDictFormat.java b/common/src/main/java/com/ycl/common/utils/excel/annotation/ExcelDictFormat.java new file mode 100644 index 0000000..7205c59 --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/annotation/ExcelDictFormat.java @@ -0,0 +1,32 @@ +package com.ycl.common.utils.excel.annotation; + + +import com.ycl.common.utils.excel.utils.StringUtils; + +import java.lang.annotation.*; + +/** + * 瀛楀吀鏍煎紡鍖� + * + * @author Lion Li + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelDictFormat { + /** + * 濡傛灉鏄瓧鍏哥被鍨嬶紝璇疯缃瓧鍏哥殑type鍊� (濡�: sys_user_sex) + */ + String dictType() default ""; + + /** + * 璇诲彇鍐呭杞〃杈惧紡 (濡�: 0=鐢�,1=濂�,2=鏈煡) + */ + String readConverterExp() default ""; + + /** + * 鍒嗛殧绗︼紝璇诲彇瀛楃涓茬粍鍐呭 + */ + String separator() default StringUtils.SEPARATOR; + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/annotation/ExcelEnumFormat.java b/common/src/main/java/com/ycl/common/utils/excel/annotation/ExcelEnumFormat.java new file mode 100644 index 0000000..3682609 --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/annotation/ExcelEnumFormat.java @@ -0,0 +1,30 @@ +package com.ycl.common.utils.excel.annotation; + +import java.lang.annotation.*; + +/** + * 鏋氫妇鏍煎紡鍖� + * + * @author Liang + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelEnumFormat { + + /** + * 瀛楀吀鏋氫妇绫诲瀷 + */ + Class<? extends Enum<?>> enumClass(); + + /** + * 瀛楀吀鏋氫妇绫讳腑瀵瑰簲鐨刢ode灞炴�у悕绉帮紝榛樿涓篶ode + */ + String codeField() default "code"; + + /** + * 瀛楀吀鏋氫妇绫讳腑瀵瑰簲鐨則ext灞炴�у悕绉帮紝榛樿涓簍ext + */ + String textField() default "text"; + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/convert/ExcelBigNumberConvert.java b/common/src/main/java/com/ycl/common/utils/excel/convert/ExcelBigNumberConvert.java new file mode 100644 index 0000000..50735ea --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/convert/ExcelBigNumberConvert.java @@ -0,0 +1,52 @@ +package com.ycl.common.utils.excel.convert; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; + +/** + * 澶ф暟鍊艰浆鎹� + * Excel 鏁板�奸暱搴︿綅15浣� 澶т簬15浣嶇殑鏁板�艰浆鎹綅瀛楃涓� + * + * @author Lion Li + */ +@Slf4j +public class ExcelBigNumberConvert implements Converter<Long> { + + @Override + public Class<Long> supportJavaTypeKey() { + return Long.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Long convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return Convert.toLong(cellData.getData()); + } + + @Override + public WriteCellData<Object> convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNotNull(object)) { + String str = Convert.toStr(object); + if (str.length() > 15) { + return new WriteCellData<>(str); + } + } + WriteCellData<Object> cellData = new WriteCellData<>(new BigDecimal(object)); + cellData.setType(CellDataTypeEnum.NUMBER); + return cellData; + } + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/convert/ExcelEnumConvert.java b/common/src/main/java/com/ycl/common/utils/excel/convert/ExcelEnumConvert.java new file mode 100644 index 0000000..b2479fb --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/convert/ExcelEnumConvert.java @@ -0,0 +1,87 @@ +package com.ycl.common.utils.excel.convert; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.ycl.common.utils.excel.annotation.ExcelEnumFormat; +import com.ycl.common.utils.reflect.ReflectUtils; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * 鏋氫妇鏍煎紡鍖栬浆鎹㈠鐞� + * + * @author Liang + */ +@Slf4j +public class ExcelEnumConvert implements Converter<Object> { + + @Override + public Class<Object> supportJavaTypeKey() { + return Object.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + cellData.checkEmpty(); + // Excel涓~鍏ョ殑鏄灇涓句腑鎸囧畾鐨勬弿杩� + Object textValue = switch (cellData.getType()) { + case STRING, DIRECT_STRING, RICH_TEXT_STRING -> cellData.getStringValue(); + case NUMBER -> cellData.getNumberValue(); + case BOOLEAN -> cellData.getBooleanValue(); + default -> throw new IllegalArgumentException("鍗曞厓鏍肩被鍨嬪紓甯�!"); + }; + // 濡傛灉鏄┖鍊� + if (ObjectUtil.isNull(textValue)) { + return null; + } + Map<Object, String> enumCodeToTextMap = beforeConvert(contentProperty); + // 浠嶫ava杈撳嚭鑷矱xcel鏄痗ode杞瑃ext + // 鍥犳浠嶦xcel杞琂ava搴旇灏唗ext涓巆ode瀵硅皟 + Map<Object, Object> enumTextToCodeMap = new HashMap<>(); + enumCodeToTextMap.forEach((key, value) -> enumTextToCodeMap.put(value, key)); + // 搴旇浠巘ext -> code涓煡鎵� + Object codeValue = enumTextToCodeMap.get(textValue); + return Convert.convert(contentProperty.getField().getType(), codeValue); + } + + @Override + public WriteCellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNull(object)) { + return new WriteCellData<>(""); + } + Map<Object, String> enumValueMap = beforeConvert(contentProperty); + String value = Convert.toStr(enumValueMap.get(object), ""); + return new WriteCellData<>(value); + } + + private Map<Object, String> beforeConvert(ExcelContentProperty contentProperty) { + ExcelEnumFormat anno = getAnnotation(contentProperty.getField()); + Map<Object, String> enumValueMap = new HashMap<>(); + Enum<?>[] enumConstants = anno.enumClass().getEnumConstants(); + for (Enum<?> enumConstant : enumConstants) { + Object codeValue = ReflectUtils.invokeGetter(enumConstant, anno.codeField()); + String textValue = ReflectUtils.invokeGetter(enumConstant, anno.textField()); + enumValueMap.put(codeValue, textValue); + } + return enumValueMap; + } + + private ExcelEnumFormat getAnnotation(Field field) { + return AnnotationUtil.getAnnotation(field, ExcelEnumFormat.class); + } +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/core/CellMergeStrategy.java b/common/src/main/java/com/ycl/common/utils/excel/core/CellMergeStrategy.java new file mode 100644 index 0000000..eb38e47 --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/core/CellMergeStrategy.java @@ -0,0 +1,157 @@ +package com.ycl.common.utils.excel.core; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.WorkbookWriteHandler; +import com.alibaba.excel.write.handler.context.WorkbookWriteHandlerContext; +import com.alibaba.excel.write.merge.AbstractMergeStrategy; +import com.ycl.common.utils.excel.annotation.CellMerge; +import com.ycl.common.utils.excel.utils.ReflectUtils; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; + +import java.lang.reflect.Field; +import java.util.*; + +/** + * 鍒楀�奸噸澶嶅悎骞剁瓥鐣� + * + * @author Lion Li + */ +@Slf4j +public class CellMergeStrategy extends AbstractMergeStrategy implements WorkbookWriteHandler { + + private final List<CellRangeAddress> cellList; + private final boolean hasTitle; + private int rowIndex; + + public CellMergeStrategy(List<?> list, boolean hasTitle) { + this.hasTitle = hasTitle; + // 琛屽悎骞跺紑濮嬩笅鏍� + this.rowIndex = hasTitle ? 1 : 0; + this.cellList = handle(list, hasTitle); + } + + @Override + protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { + //鍗曞厓鏍煎啓鍏ヤ簡,閬嶅巻鍚堝苟鍖哄煙,濡傛灉璇ell鍦ㄥ尯鍩熷唴,浣嗛潪棣栬,鍒欐竻绌� + final int rowIndex = cell.getRowIndex(); + if (CollUtil.isNotEmpty(cellList)){ + for (CellRangeAddress cellAddresses : cellList) { + final int firstRow = cellAddresses.getFirstRow(); + if (cellAddresses.isInRange(cell) && rowIndex != firstRow){ + cell.setBlank(); + } + } + } + } + + @Override + public void afterWorkbookDispose(final WorkbookWriteHandlerContext context) { + //褰撳墠琛ㄦ牸鍐欏畬鍚庯紝缁熶竴鍐欏叆 + if (CollUtil.isNotEmpty(cellList)){ + for (CellRangeAddress item : cellList) { + context.getWriteContext().writeSheetHolder().getSheet().addMergedRegion(item); + } + } + } + + @SneakyThrows + private List<CellRangeAddress> handle(List<?> list, boolean hasTitle) { + List<CellRangeAddress> cellList = new ArrayList<>(); + if (CollUtil.isEmpty(list)) { + return cellList; + } + Field[] fields = ReflectUtils.getFields(list.get(0).getClass(), field -> !"serialVersionUID".equals(field.getName())); + + // 鏈夋敞瑙g殑瀛楁 + List<Field> mergeFields = new ArrayList<>(); + List<Integer> mergeFieldsIndex = new ArrayList<>(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (field.isAnnotationPresent(CellMerge.class)) { + CellMerge cm = field.getAnnotation(CellMerge.class); + mergeFields.add(field); + mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index()); + if (hasTitle) { + ExcelProperty property = field.getAnnotation(ExcelProperty.class); + rowIndex = Math.max(rowIndex, property.value().length); + } + } + } + + Map<Field, RepeatCell> map = new HashMap<>(); + // 鐢熸垚涓や袱鍚堝苟鍗曞厓鏍� + for (int i = 0; i < list.size(); i++) { + for (int j = 0; j < mergeFields.size(); j++) { + Field field = mergeFields.get(j); + Object val = ReflectUtils.invokeGetter(list.get(i), field.getName()); + + int colNum = mergeFieldsIndex.get(j); + if (!map.containsKey(field)) { + map.put(field, new RepeatCell(val, i)); + } else { + RepeatCell repeatCell = map.get(field); + Object cellValue = repeatCell.getValue(); + if (cellValue == null || "".equals(cellValue)) { + // 绌哄�艰烦杩囦笉鍚堝苟 + continue; + } + + if (!cellValue.equals(val)) { + if ((i - repeatCell.getCurrent() > 1)) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); + } + map.put(field, new RepeatCell(val, i)); + } else if (i == list.size() - 1) { + if (i > repeatCell.getCurrent() && isMerge(list, i, field)) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); + } + } else if (!isMerge(list, i, field)) { + if ((i - repeatCell.getCurrent() > 1)) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); + } + map.put(field, new RepeatCell(val, i)); + } + } + } + } + return cellList; + } + + private boolean isMerge(List<?> list, int i, Field field) { + boolean isMerge = true; + CellMerge cm = field.getAnnotation(CellMerge.class); + final String[] mergeBy = cm.mergeBy(); + if (StrUtil.isAllNotBlank(mergeBy)) { + //姣斿褰撳墠list(i)鍜宭ist(i - 1)鐨勫悇涓睘鎬у�间竴涓�姣斿 濡傛灉鍏ㄤ负鐪� 鍒欎负鐪� + for (String fieldName : mergeBy) { + final Object valCurrent = ReflectUtil.getFieldValue(list.get(i), fieldName); + final Object valPre = ReflectUtil.getFieldValue(list.get(i - 1), fieldName); + if (!Objects.equals(valPre, valCurrent)) { + //渚濊禆瀛楁濡傛湁浠讳竴涓嶇瓑鍊�,鍒欐爣璁颁负涓嶅彲鍚堝苟 + isMerge = false; + } + } + } + return isMerge; + } + + @Data + @AllArgsConstructor + static class RepeatCell { + + private Object value; + + private int current; + + } +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/core/DefaultExcelListener.java b/common/src/main/java/com/ycl/common/utils/excel/core/DefaultExcelListener.java new file mode 100644 index 0000000..04390be --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/core/DefaultExcelListener.java @@ -0,0 +1,104 @@ +package com.ycl.common.utils.excel.core; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.ycl.common.utils.excel.utils.JsonUtils; +import com.ycl.common.utils.excel.utils.StreamUtils; +import com.ycl.common.utils.excel.utils.ValidatorUtils; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import java.util.Map; +import java.util.Set; + +/** + * Excel 瀵煎叆鐩戝惉 + * + * @author Yjoioooo + * @author Lion Li + */ +@Slf4j +@NoArgsConstructor +public class DefaultExcelListener<T> extends AnalysisEventListener<T> implements ExcelListener<T> { + + /** + * 鏄惁Validator妫�楠岋紝榛樿涓烘槸 + */ + private Boolean isValidate = Boolean.TRUE; + + /** + * excel 琛ㄥご鏁版嵁 + */ + private Map<Integer, String> headMap; + + /** + * 瀵煎叆鍥炴墽 + */ + private ExcelResult<T> excelResult; + + public DefaultExcelListener(boolean isValidate) { + this.excelResult = new DefaultExcelResult<>(); + this.isValidate = isValidate; + } + + /** + * 澶勭悊寮傚父 + * + * @param exception ExcelDataConvertException + * @param context Excel 涓婁笅鏂� + */ + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + String errMsg = null; + if (exception instanceof ExcelDataConvertException excelDataConvertException) { + // 濡傛灉鏄煇涓�涓崟鍏冩牸鐨勮浆鎹㈠紓甯� 鑳借幏鍙栧埌鍏蜂綋琛屽彿 + Integer rowIndex = excelDataConvertException.getRowIndex(); + Integer columnIndex = excelDataConvertException.getColumnIndex(); + errMsg = StrUtil.format("绗瑊}琛�-绗瑊}鍒�-琛ㄥご{}: 瑙f瀽寮傚父<br/>", + rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + if (exception instanceof ConstraintViolationException constraintViolationException) { + Set<ConstraintViolation<?>> constraintViolations = constraintViolationException.getConstraintViolations(); + String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", "); + errMsg = StrUtil.format("绗瑊}琛屾暟鎹牎楠屽紓甯�: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + excelResult.getErrorList().add(errMsg); + throw new ExcelAnalysisException(errMsg); + } + + @Override + public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) { + this.headMap = headMap; + log.debug("瑙f瀽鍒颁竴鏉¤〃澶存暟鎹�: {}", JsonUtils.toJsonString(headMap)); + } + + @Override + public void invoke(T data, AnalysisContext context) { + if (isValidate) { + ValidatorUtils.validate(data); + } + excelResult.getList().add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + log.debug("鎵�鏈夋暟鎹В鏋愬畬鎴愶紒"); + } + + @Override + public ExcelResult<T> getExcelResult() { + return excelResult; + } + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/core/DefaultExcelResult.java b/common/src/main/java/com/ycl/common/utils/excel/core/DefaultExcelResult.java new file mode 100644 index 0000000..d61b3ab --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/core/DefaultExcelResult.java @@ -0,0 +1,73 @@ +package com.ycl.common.utils.excel.core; + +import cn.hutool.core.util.StrUtil; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 榛樿excel杩斿洖瀵硅薄 + * + * @author Yjoioooo + * @author Lion Li + */ +public class DefaultExcelResult<T> implements ExcelResult<T> { + + /** + * 鏁版嵁瀵硅薄list + */ + @Setter + private List<T> list; + + /** + * 閿欒淇℃伅鍒楄〃 + */ + @Setter + private List<String> errorList; + + public DefaultExcelResult() { + this.list = new ArrayList<>(); + this.errorList = new ArrayList<>(); + } + + public DefaultExcelResult(List<T> list, List<String> errorList) { + this.list = list; + this.errorList = errorList; + } + + public DefaultExcelResult(ExcelResult<T> excelResult) { + this.list = excelResult.getList(); + this.errorList = excelResult.getErrorList(); + } + + @Override + public List<T> getList() { + return list; + } + + @Override + public List<String> getErrorList() { + return errorList; + } + + /** + * 鑾峰彇瀵煎叆鍥炴墽 + * + * @return 瀵煎叆鍥炴墽 + */ + @Override + public String getAnalysis() { + int successCount = list.size(); + int errorCount = errorList.size(); + if (successCount == 0) { + return "璇诲彇澶辫触锛屾湭瑙f瀽鍒版暟鎹�"; + } else { + if (errorCount == 0) { + return StrUtil.format("鎭枩鎮紝鍏ㄩ儴璇诲彇鎴愬姛锛佸叡{}鏉�", successCount); + } else { + return ""; + } + } + } +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/core/DropDownOptions.java b/common/src/main/java/com/ycl/common/utils/excel/core/DropDownOptions.java new file mode 100644 index 0000000..aa0d9f7 --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/core/DropDownOptions.java @@ -0,0 +1,149 @@ +package com.ycl.common.utils.excel.core; + +import cn.hutool.core.util.StrUtil; +import com.ycl.common.exception.ServiceException; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * <h1>Excel涓嬫媺鍙�夐」</h1> + * 娉ㄦ剰锛氫负纭繚涓嬫媺妗嗚В鏋愭纭紝浼犲�煎姟蹇呬娇鐢╟reateOptionValue()鍋氫负鍊肩殑鎷兼帴 + * + * @author Emil.Zhang + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuppressWarnings("unused") +public class DropDownOptions { + /** + * 涓�绾т笅鎷夋墍鍦ㄥ垪index锛屼粠0寮�濮嬬畻 + */ + private int index = 0; + /** + * 浜岀骇涓嬫媺鎵�鍦ㄧ殑index锛屼粠0寮�濮嬬畻锛屼笉鑳戒笌涓�绾х浉鍚� + */ + private int nextIndex = 0; + /** + * 涓�绾т笅鎷夋墍鍖呭惈鐨勬暟鎹� + */ + private List<String> options = new ArrayList<>(); + /** + * 浜岀骇涓嬫媺鎵�鍖呭惈鐨勬暟鎹甅ap + * <p>浠ユ瘡涓�涓竴绾ч�夐」鍊间负Key锛屾瘡涓竴绾ч�夐」瀵瑰簲鐨勪簩绾ф暟鎹负Value</p> + */ + private Map<String, List<String>> nextOptions = new HashMap<>(); + /** + * 鍒嗛殧绗� + */ + private static final String DELIMITER = "_"; + + /** + * 鍒涘缓鍙湁涓�绾х殑涓嬫媺閫� + */ + public DropDownOptions(int index, List<String> options) { + this.index = index; + this.options = options; + } + + /** + * <h2>鍒涘缓姣忎釜閫夐」鍙�夊��</h2> + * <p>娉ㄦ剰锛氫笉鑳戒互鏁板瓧锛岀壒娈婄鍙峰紑澶达紝閫夐」涓笉鍙互鍖呭惈浠讳綍杩愮畻绗﹀彿</p> + * + * @param vars 鍙�夊�煎唴鍖呭惈鐨勫弬鏁� + * @return 鍚堣鐨勫彲閫夊�� + */ + public static String createOptionValue(Object... vars) { + StringBuilder stringBuffer = new StringBuilder(); + String regex = "^[\\S\\d\\u4e00-\\u9fa5]+$"; + for (int i = 0; i < vars.length; i++) { + String var = StrUtil.trimToEmpty(String.valueOf(vars[i])); + if (!var.matches(regex)) { + throw new ServiceException("閫夐」鏁版嵁涓嶇鍚堣鍒欙紝浠呭厑璁镐娇鐢ㄤ腑鑻辨枃瀛楃浠ュ強鏁板瓧"); + } + stringBuffer.append(var); + if (i < vars.length - 1) { + // 鐩磋嚦鏈�鍚庝竴涓墠锛岄兘浠浣滀负鍒囧壊绾� + stringBuffer.append(DELIMITER); + } + } + if (stringBuffer.toString().matches("^\\d_*$")) { + throw new ServiceException("绂佹浠ユ暟瀛楀紑澶�"); + } + return stringBuffer.toString(); + } + + /** + * 灏嗗鐞嗗悗鍚堢悊鐨勫彲閫夊�艰В鏋愪负鍘熷鐨勫弬鏁� + * + * @param option 缁忚繃澶勭悊鍚庣殑鍚堢悊鐨勫彲閫夐」 + * @return 鍘熷鐨勫弬鏁� + */ + public static List<String> analyzeOptionValue(String option) { + return StrUtil.split(option, DELIMITER, true, true); + } + + /** + * 鍒涘缓绾ц仈涓嬫媺閫夐」 + * + * @param parentList 鐖跺疄浣撳彲閫夐」鍘熷鏁版嵁 + * @param parentIndex 鐖朵笅鎷夐�変綅缃� + * @param sonList 瀛愬疄浣撳彲閫夐」鍘熷鏁版嵁 + * @param sonIndex 瀛愪笅鎷夐�変綅缃� + * @param parentHowToGetIdFunction 鐖剁被濡備綍鑾峰彇鍞竴鏍囪瘑 + * @param sonHowToGetParentIdFunction 瀛愮被濡備綍鑾峰彇鐖剁被鐨勫敮涓�鏍囪瘑 + * @param howToBuildEveryOption 濡備綍鐢熸垚涓嬫媺閫夊唴瀹� + * @return 绾ц仈涓嬫媺閫夐」 + */ + public static <T> DropDownOptions buildLinkedOptions(List<T> parentList, + int parentIndex, + List<T> sonList, + int sonIndex, + Function<T, Number> parentHowToGetIdFunction, + Function<T, Number> sonHowToGetParentIdFunction, + Function<T, String> howToBuildEveryOption) { + DropDownOptions parentLinkSonOptions = new DropDownOptions(); + // 鍏堝垱寤虹埗绫荤殑涓嬫媺 + parentLinkSonOptions.setIndex(parentIndex); + parentLinkSonOptions.setOptions( + parentList.stream() + .map(howToBuildEveryOption) + .collect(Collectors.toList()) + ); + // 鎻愬彇鐖�-瀛愮骇鑱斾笅鎷� + Map<String, List<String>> sonOptions = new HashMap<>(); + // 鐖剁骇渚濇嵁鑷繁鐨処D鍒嗙粍 + Map<Number, List<T>> parentGroupByIdMap = + parentList.stream().collect(Collectors.groupingBy(parentHowToGetIdFunction)); + // 閬嶅巻姣忎釜瀛愰泦锛屾彁鍙栧埌Map涓� + sonList.forEach(everySon -> { + if (parentGroupByIdMap.containsKey(sonHowToGetParentIdFunction.apply(everySon))) { + // 鎵惧埌瀵瑰簲鐨勪笂绾� + T parentObj = parentGroupByIdMap.get(sonHowToGetParentIdFunction.apply(everySon)).get(0); + // 鎻愬彇鍚嶇О鍜孖D浣滀负Key + String key = howToBuildEveryOption.apply(parentObj); + // Key瀵瑰簲鐨刅alue + List<String> thisParentSonOptionList; + if (sonOptions.containsKey(key)) { + thisParentSonOptionList = sonOptions.get(key); + } else { + thisParentSonOptionList = new ArrayList<>(); + sonOptions.put(key, thisParentSonOptionList); + } + // 寰�Value涓坊鍔犲綋鍓嶅瓙闆嗛�夐」 + thisParentSonOptionList.add(howToBuildEveryOption.apply(everySon)); + } + }); + parentLinkSonOptions.setNextIndex(sonIndex); + parentLinkSonOptions.setNextOptions(sonOptions); + return parentLinkSonOptions; + } +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/core/ExcelDownHandler.java b/common/src/main/java/com/ycl/common/utils/excel/core/ExcelDownHandler.java new file mode 100644 index 0000000..47ad684 --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/core/ExcelDownHandler.java @@ -0,0 +1,373 @@ +package com.ycl.common.utils.excel.core; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.EnumUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.metadata.FieldCache; +import com.alibaba.excel.metadata.FieldWrapper; +import com.alibaba.excel.util.ClassUtils; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import com.ycl.common.exception.ServiceException; +import com.ycl.common.utils.excel.annotation.ExcelDictFormat; +import com.ycl.common.utils.excel.annotation.ExcelEnumFormat; +import com.ycl.common.utils.excel.service.DictService; +import com.ycl.common.utils.excel.utils.StreamUtils; +import com.ycl.common.utils.excel.utils.StringUtils; +import com.ycl.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.ss.util.WorkbookUtil; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; + +import java.lang.reflect.Field; +import java.util.*; + +/** + * <h1>Excel琛ㄦ牸涓嬫媺閫夋搷浣�</h1> + * 鑰冭檻鍒颁笅鎷夐�夎繃澶氬彲鑳藉鑷碋xcel鎵撳紑缂撴參鐨勯棶棰橈紝鍙牎楠屽墠1000琛� + * <p> + * 鍗冲彧鏈夊墠1000琛岀殑鏁版嵁鍙互鐢ㄤ笅鎷夋锛岃秴鍑虹殑鑷閫氳繃闄愬埗鏁版嵁閲忕殑褰㈠紡锛岀浜屾杈撳嚭 + * + * @author Emil.Zhang + */ +@Slf4j +public class ExcelDownHandler implements SheetWriteHandler { + + /** + * Excel琛ㄦ牸涓殑鍒楀悕鑻辨枃 + * 浠呬负浜嗚В鏋愬垪鑻辨枃锛岀姝慨鏀� + */ + private static final String EXCEL_COLUMN_NAME = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + /** + * 鍗曢�夋暟鎹甋heet鍚� + */ + private static final String OPTIONS_SHEET_NAME = "options"; + /** + * 鑱斿姩閫夋嫨鏁版嵁Sheet鍚嶇殑澶� + */ + private static final String LINKED_OPTIONS_SHEET_NAME = "linkedOptions"; + /** + * 涓嬫媺鍙�夐」 + */ + private final List<DropDownOptions> dropDownOptions; + /** + * 褰撳墠鍗曢�夎繘搴� + */ + private int currentOptionsColumnIndex; + /** + * 褰撳墠鑱斿姩閫夋嫨杩涘害 + */ + private int currentLinkedOptionsSheetIndex; + private final DictService dictService; + + public ExcelDownHandler(List<DropDownOptions> options) { + this.dropDownOptions = options; + this.currentOptionsColumnIndex = 0; + this.currentLinkedOptionsSheetIndex = 0; + this.dictService = SpringUtils.getBean(DictService.class); + } + + /** + * <h2>寮�濮嬪垱寤轰笅鎷夋暟鎹�</h2> + * 1.閫氳繃瑙f瀽浼犲叆鐨凘ExcelProperty鍚岀骇鏄惁鏍囨敞鏈堾DropDown閫夐」 + * 濡傛灉鏈変笖璁剧疆浜唙alue鍊硷紝鍒欏皢鍏剁洿鎺ョ疆涓轰笅鎷夊彲閫夐」 + * <p> + * 2.鎴栬�呭湪璋冪敤ExcelUtil鏃舵寚瀹氫簡鍙�夐」锛屽皢渚濇嵁浼犲叆鐨勫彲閫夐」鍋氫笅鎷� + * <p> + * 3.浜岃�呭苟瀛橈紝娉ㄦ剰璋冪敤鏂瑰紡 + */ + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + Sheet sheet = writeSheetHolder.getSheet(); + // 寮�濮嬭缃笅鎷夋 HSSFWorkbook + DataValidationHelper helper = sheet.getDataValidationHelper(); + Workbook workbook = writeWorkbookHolder.getWorkbook(); + FieldCache fieldCache = ClassUtils.declaredFields(writeWorkbookHolder.getClazz(), writeWorkbookHolder); + for (Map.Entry<Integer, FieldWrapper> entry : fieldCache.getSortedFieldMap().entrySet()) { + Integer index = entry.getKey(); + FieldWrapper wrapper = entry.getValue(); + Field field = wrapper.getField(); + // 寰幆瀹炰綋涓殑姣忎釜灞炴�� + // 鍙�夌殑涓嬫媺鍊� + List<String> options = new ArrayList<>(); + if (field.isAnnotationPresent(ExcelDictFormat.class)) { + // 濡傛灉鎸囧畾浜咢ExcelDictFormat锛屽垯浣跨敤瀛楀吀鐨勯�昏緫 + ExcelDictFormat format = field.getDeclaredAnnotation(ExcelDictFormat.class); + String dictType = format.dictType(); + String converterExp = format.readConverterExp(); + if (StringUtils.isNotBlank(dictType)) { + // 濡傛灉浼犻�掍簡瀛楀吀鍚嶏紝鍒欎緷鎹瓧鍏稿缓绔嬩笅鎷� + Collection<String> values = Optional.ofNullable(dictService.getAllDictByDictType(dictType)) + .orElseThrow(() -> new ServiceException(String.format("瀛楀吀 %s 涓嶅瓨鍦�", dictType))) + .values(); + options = new ArrayList<>(values); + } else if (StringUtils.isNotBlank(converterExp)) { + // 濡傛灉鎸囧畾浜嗙‘鍒囩殑鍊硷紝鍒欑洿鎺ヨВ鏋愮‘鍒囩殑鍊� + List<String> strList = StringUtils.splitList(converterExp, format.separator()); + options = StreamUtils.toList(strList, s -> StringUtils.split(s, "=")[1]); + } + } else if (field.isAnnotationPresent(ExcelEnumFormat.class)) { + // 鍚﹀垯濡傛灉鎸囧畾浜咢ExcelEnumFormat锛屽垯浣跨敤鏋氫妇鐨勯�昏緫 + ExcelEnumFormat format = field.getDeclaredAnnotation(ExcelEnumFormat.class); + List<Object> values = EnumUtil.getFieldValues(format.enumClass(), format.textField()); + options = StreamUtils.toList(values, String::valueOf); + } + if (ObjectUtil.isNotEmpty(options)) { + // 浠呭綋涓嬫媺鍙�夐」涓嶄负绌烘椂鎵ц + if (options.size() > 20) { + // 杩欓噷闄愬埗濡傛灉鍙�夐」澶т簬20锛屽垯浣跨敤棰濆琛ㄥ舰寮� + dropDownWithSheet(helper, workbook, sheet, index, options); + } else { + // 鍚﹀垯浣跨敤鍥哄畾鍊煎舰寮� + dropDownWithSimple(helper, sheet, index, options); + } + } + } + if (CollUtil.isEmpty(dropDownOptions)) { + return; + } + dropDownOptions.forEach(everyOptions -> { + // 濡傛灉浼犻�掍簡涓嬫媺妗嗛�夋嫨鍣ㄥ弬鏁� + if (!everyOptions.getNextOptions().isEmpty()) { + // 褰撲簩绾ч�夐」涓嶄负绌烘椂锛屼娇鐢ㄩ澶栧叧鑱旇〃鐨勫舰寮� + dropDownLinkedOptions(helper, workbook, sheet, everyOptions); + } else if (everyOptions.getOptions().size() > 10) { + // 褰撲竴绾ч�夐」鍙傛暟涓暟澶т簬10锛屼娇鐢ㄩ澶栬〃鐨勫舰寮� + dropDownWithSheet(helper, workbook, sheet, everyOptions.getIndex(), everyOptions.getOptions()); + } else if (everyOptions.getOptions().size() != 0) { + // 褰撲竴绾ч�夐」涓暟涓嶄负绌猴紝浣跨敤榛樿褰㈠紡 + dropDownWithSimple(helper, sheet, everyOptions.getIndex(), everyOptions.getOptions()); + } + }); + } + + /** + * <h2>绠�鍗曚笅鎷夋</h2> + * 鐩存帴灏嗗彲閫夐」鎷兼帴涓烘寚瀹氬垪鐨勬暟鎹牎楠屽�� + * + * @param celIndex 鍒梚ndex + * @param value 涓嬫媺閫夊彲閫夊�� + */ + private void dropDownWithSimple(DataValidationHelper helper, Sheet sheet, Integer celIndex, List<String> value) { + if (ObjectUtil.isEmpty(value)) { + return; + } + this.markOptionsToSheet(helper, sheet, celIndex, helper.createExplicitListConstraint(ArrayUtil.toArray(value, String.class))); + } + + /** + * <h2>棰濆琛ㄦ牸褰㈠紡鐨勭骇鑱斾笅鎷夋</h2> + * + * @param options 棰濆琛ㄦ牸褰㈠紡瀛樺偍鐨勪笅鎷夊彲閫夐」 + */ + private void dropDownLinkedOptions(DataValidationHelper helper, Workbook workbook, Sheet sheet, DropDownOptions options) { + String linkedOptionsSheetName = String.format("%s_%d", LINKED_OPTIONS_SHEET_NAME, currentLinkedOptionsSheetIndex); + // 鍒涘缓鑱斿姩涓嬫媺鏁版嵁琛� + Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName)); + // 灏嗕笅鎷夎〃闅愯棌 + workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true); + // 瀹屽杽妯悜鐨勪竴绾ч�夐」鏁版嵁琛� + List<String> firstOptions = options.getOptions(); + Map<String, List<String>> secoundOptionsMap = options.getNextOptions(); + + // 鍒涘缓鍚嶇О绠$悊鍣� + Name name = workbook.createName(); + // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑鍒悕 + name.setNameName(linkedOptionsSheetName); + // 浠ユí鍚戠涓�琛屽垱寤轰竴绾т笅鎷夋嫾鎺ュ紩鐢ㄤ綅缃� + String firstOptionsFunction = String.format("%s!$%s$1:$%s$1", + linkedOptionsSheetName, + getExcelColumnName(0), + getExcelColumnName(firstOptions.size()) + ); + // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑寮曠敤浣嶇疆 + name.setRefersToFormula(firstOptionsFunction); + // 璁剧疆鏁版嵁鏍¢獙涓哄簭鍒楁ā寮忥紝寮曠敤鐨勬槸鍚嶇О绠$悊鍣ㄤ腑鐨勫埆鍚� + this.markOptionsToSheet(helper, sheet, options.getIndex(), helper.createFormulaListConstraint(linkedOptionsSheetName)); + + for (int columIndex = 0; columIndex < firstOptions.size(); columIndex++) { + // 鍏堟彁鍙栦富琛ㄤ腑涓�绾т笅鎷夌殑鍒楀悕 + String firstOptionsColumnName = getExcelColumnName(columIndex); + // 涓�娆″惊鐜槸姣忎竴涓竴绾ч�夐」 + int finalI = columIndex; + // 鏈寰幆鐨勪竴绾ч�夐」鍊� + String thisFirstOptionsValue = firstOptions.get(columIndex); + // 鍒涘缓绗竴琛岀殑鏁版嵁 + Optional.ofNullable(linkedOptionsDataSheet.getRow(0)) + // 濡傛灉涓嶅瓨鍦ㄥ垯鍒涘缓绗竴琛� + .orElseGet(() -> linkedOptionsDataSheet.createRow(finalI)) + // 绗竴琛屽綋鍓嶅垪 + .createCell(columIndex) + // 璁剧疆鍊间负褰撳墠涓�绾ч�夐」鍊� + .setCellValue(thisFirstOptionsValue); + + // 绗簩琛屽紑濮嬶紝璁剧疆绗簩绾у埆閫夐」鍙傛暟 + List<String> secondOptions = secoundOptionsMap.get(thisFirstOptionsValue); + if (CollUtil.isEmpty(secondOptions)) { + // 蹇呴』淇濊瘉鑷冲皯鏈変竴涓叧鑱旈�夐」锛屽惁鍒欏皢瀵艰嚧Excel瑙f瀽閿欒 + secondOptions = Collections.singletonList("鏆傛棤_0"); + } + + // 浠ヨ涓�绾ч�夐」鍊煎垱寤哄瓙鍚嶇О绠$悊鍣� + Name sonName = workbook.createName(); + // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑鍒悕 + sonName.setNameName(thisFirstOptionsValue); + // 浠ョ浜岃璇ュ垪鏁版嵁鎷兼帴寮曠敤浣嶇疆 + String sonFunction = String.format("%s!$%s$2:$%s$%d", + linkedOptionsSheetName, + firstOptionsColumnName, + firstOptionsColumnName, + secondOptions.size() + 1 + ); + // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑寮曠敤浣嶇疆 + sonName.setRefersToFormula(sonFunction); + // 鏁版嵁楠岃瘉涓哄簭鍒楁ā寮忥紝寮曠敤鍒版瘡涓�涓富琛ㄤ腑鐨勪簩绾ч�夐」浣嶇疆 + // 鍒涘缓瀛愰」鐨勫悕绉扮鐞嗗櫒锛屽彧鏄负浜嗕娇寰桬xcel鍙互璇嗗埆鍒版暟鎹� + String mainSheetFirstOptionsColumnName = getExcelColumnName(options.getIndex()); + for (int i = 0; i < 100; i++) { + // 浠ヤ竴绾ч�夐」瀵瑰簲鐨勪富浣撴墍鍦ㄤ綅缃垱寤轰簩绾т笅鎷� + String secondOptionsFunction = String.format("=INDIRECT(%s%d)", mainSheetFirstOptionsColumnName, i + 1); + // 浜岀骇鍙兘涓昏〃姣忎竴琛岀殑姣忎竴鍒楁坊鍔犱簩绾ф牎楠� + markLinkedOptionsToSheet(helper, sheet, i, options.getNextIndex(), helper.createFormulaListConstraint(secondOptionsFunction)); + } + + for (int rowIndex = 0; rowIndex < secondOptions.size(); rowIndex++) { + // 浠庣浜岃寮�濮嬪~鍏呬簩绾ч�夐」 + int finalRowIndex = rowIndex + 1; + int finalColumIndex = columIndex; + + Row row = Optional.ofNullable(linkedOptionsDataSheet.getRow(finalRowIndex)) + // 娌℃湁鍒欏垱寤� + .orElseGet(() -> linkedOptionsDataSheet.createRow(finalRowIndex)); + Optional + // 鍦ㄦ湰绾т竴绾ч�夐」鎵�鍦ㄧ殑鍒� + .ofNullable(row.getCell(finalColumIndex)) + // 涓嶅瓨鍦ㄥ垯鍒涘缓 + .orElseGet(() -> row.createCell(finalColumIndex)) + // 璁剧疆浜岀骇閫夐」鍊� + .setCellValue(secondOptions.get(rowIndex)); + } + } + + currentLinkedOptionsSheetIndex++; + } + + /** + * <h2>棰濆琛ㄦ牸褰㈠紡鐨勬櫘閫氫笅鎷夋</h2> + * 鐢变簬涓嬫媺妗嗗彲閫夊�兼暟閲忚繃澶氾紝涓烘彁鍗嘐xcel鎵撳紑鏁堢巼锛屼娇鐢ㄩ澶栬〃鏍煎舰寮忓仛涓嬫媺 + * + * @param celIndex 涓嬫媺閫� + * @param value 涓嬫媺閫夊彲閫夊�� + */ + private void dropDownWithSheet(DataValidationHelper helper, Workbook workbook, Sheet sheet, Integer celIndex, List<String> value) { + // 鍒涘缓涓嬫媺鏁版嵁琛� + Sheet simpleDataSheet = Optional.ofNullable(workbook.getSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME))) + .orElseGet(() -> workbook.createSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME))); + // 灏嗕笅鎷夎〃闅愯棌 + workbook.setSheetHidden(workbook.getSheetIndex(simpleDataSheet), true); + // 瀹屽杽绾靛悜鐨勪竴绾ч�夐」鏁版嵁琛� + for (int i = 0; i < value.size(); i++) { + int finalI = i; + // 鑾峰彇姣忎竴閫夐」琛岋紝濡傛灉娌℃湁鍒欏垱寤� + Row row = Optional.ofNullable(simpleDataSheet.getRow(i)) + .orElseGet(() -> simpleDataSheet.createRow(finalI)); + // 鑾峰彇鏈骇閫夐」瀵瑰簲鐨勯�夐」鍒楋紝濡傛灉娌℃湁鍒欏垱寤� + Cell cell = Optional.ofNullable(row.getCell(currentOptionsColumnIndex)) + .orElseGet(() -> row.createCell(currentOptionsColumnIndex)); + // 璁剧疆鍊� + cell.setCellValue(value.get(i)); + } + + // 鍒涘缓鍚嶇О绠$悊鍣� + Name name = workbook.createName(); + // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑鍒悕 + String nameName = String.format("%s_%d", OPTIONS_SHEET_NAME, celIndex); + name.setNameName(nameName); + // 浠ョ旱鍚戠涓�鍒楀垱寤轰竴绾т笅鎷夋嫾鎺ュ紩鐢ㄤ綅缃� + String function = String.format("%s!$%s$1:$%s$%d", + OPTIONS_SHEET_NAME, + getExcelColumnName(currentOptionsColumnIndex), + getExcelColumnName(currentOptionsColumnIndex), + value.size()); + // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑寮曠敤浣嶇疆 + name.setRefersToFormula(function); + // 璁剧疆鏁版嵁鏍¢獙涓哄簭鍒楁ā寮忥紝寮曠敤鐨勬槸鍚嶇О绠$悊鍣ㄤ腑鐨勫埆鍚� + this.markOptionsToSheet(helper, sheet, celIndex, helper.createFormulaListConstraint(nameName)); + currentOptionsColumnIndex++; + } + + /** + * 鎸傝浇涓嬫媺鐨勫垪锛屼粎闄愪竴绾ч�夐」 + */ + private void markOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer celIndex, + DataValidationConstraint constraint) { + // 璁剧疆鏁版嵁鏈夋晥鎬у姞杞藉湪鍝釜鍗曞厓鏍间笂,鍥涗釜鍙傛暟鍒嗗埆鏄細璧峰琛屻�佺粓姝㈣銆佽捣濮嬪垪銆佺粓姝㈠垪 + CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, celIndex, celIndex); + markDataValidationToSheet(helper, sheet, constraint, addressList); + } + + /** + * 鎸傝浇涓嬫媺鐨勫垪锛屼粎闄愪簩绾ч�夐」 + */ + private void markLinkedOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer rowIndex, + Integer celIndex, DataValidationConstraint constraint) { + // 璁剧疆鏁版嵁鏈夋晥鎬у姞杞藉湪鍝釜鍗曞厓鏍间笂,鍥涗釜鍙傛暟鍒嗗埆鏄細璧峰琛屻�佺粓姝㈣銆佽捣濮嬪垪銆佺粓姝㈠垪 + CellRangeAddressList addressList = new CellRangeAddressList(rowIndex, rowIndex, celIndex, celIndex); + markDataValidationToSheet(helper, sheet, constraint, addressList); + } + + /** + * 搴旂敤鏁版嵁鏍¢獙 + */ + private void markDataValidationToSheet(DataValidationHelper helper, Sheet sheet, + DataValidationConstraint constraint, CellRangeAddressList addressList) { + // 鏁版嵁鏈夋晥鎬у璞� + DataValidation dataValidation = helper.createValidation(constraint, addressList); + // 澶勭悊Excel鍏煎鎬ч棶棰� + if (dataValidation instanceof XSSFDataValidation) { + //鏁版嵁鏍¢獙 + dataValidation.setSuppressDropDownArrow(true); + //閿欒鎻愮ず + dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP); + dataValidation.createErrorBox("鎻愮ず", "姝ゅ�间笌鍗曞厓鏍煎畾涔夋暟鎹笉涓�鑷�"); + dataValidation.setShowErrorBox(true); + //閫夊畾鎻愮ず + dataValidation.createPromptBox("濉啓璇存槑锛�", "濉啓鍐呭鍙兘涓轰笅鎷変腑鏁版嵁锛屽叾浠栨暟鎹皢瀵艰嚧瀵煎叆澶辫触"); + dataValidation.setShowPromptBox(true); + sheet.addValidationData(dataValidation); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + sheet.addValidationData(dataValidation); + } + + /** + * <h2>渚濇嵁鍒梚ndex鑾峰彇鍒楀悕鑻辨枃</h2> + * 渚濇嵁鍒梚ndex杞崲涓篍xcel涓殑鍒楀悕鑻辨枃 + * <p>渚嬪绗�1鍒楋紝index涓�0锛岃В鏋愬嚭鏉ヤ负A鍒�</p> + * 绗�27鍒楋紝index涓�26锛岃В鏋愪负AA鍒� + * <p>绗�28鍒楋紝index涓�27锛岃В鏋愪负AB鍒�</p> + * + * @param columnIndex 鍒梚ndex + * @return 鍒梚ndex鎵�鍦ㄥ緱鑻辨枃鍚� + */ + private String getExcelColumnName(int columnIndex) { + // 26涓�寰幆鐨勬鏁� + int columnCircleCount = columnIndex / 26; + // 26涓�寰幆鍐呯殑浣嶇疆 + int thisCircleColumnIndex = columnIndex % 26; + // 26涓�寰幆鐨勬鏁板ぇ浜�0锛屽垯瑙嗕负鏍忓悕鑷冲皯涓や綅 + String columnPrefix = columnCircleCount == 0 + ? StrUtil.EMPTY + : StrUtil.subWithLength(EXCEL_COLUMN_NAME, columnCircleCount - 1, 1); + // 浠�26涓�寰幆鍐呭彇瀵瑰簲鐨勬爮浣嶅悕 + String columnNext = StrUtil.subWithLength(EXCEL_COLUMN_NAME, thisCircleColumnIndex, 1); + // 灏嗕簩鑰呮嫾鎺ュ嵆涓烘渶缁堢殑鏍忎綅鍚� + return columnPrefix + columnNext; + } +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/core/ExcelListener.java b/common/src/main/java/com/ycl/common/utils/excel/core/ExcelListener.java new file mode 100644 index 0000000..76ba16c --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/core/ExcelListener.java @@ -0,0 +1,14 @@ +package com.ycl.common.utils.excel.core; + +import com.alibaba.excel.read.listener.ReadListener; + +/** + * Excel 瀵煎叆鐩戝惉 + * + * @author Lion Li + */ +public interface ExcelListener<T> extends ReadListener<T> { + + ExcelResult<T> getExcelResult(); + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/core/ExcelResult.java b/common/src/main/java/com/ycl/common/utils/excel/core/ExcelResult.java new file mode 100644 index 0000000..36d9c8e --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/core/ExcelResult.java @@ -0,0 +1,26 @@ +package com.ycl.common.utils.excel.core; + +import java.util.List; + +/** + * excel杩斿洖瀵硅薄 + * + * @author Lion Li + */ +public interface ExcelResult<T> { + + /** + * 瀵硅薄鍒楄〃 + */ + List<T> getList(); + + /** + * 閿欒鍒楄〃 + */ + List<String> getErrorList(); + + /** + * 瀵煎叆鍥炴墽 + */ + String getAnalysis(); +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/service/DictService.java b/common/src/main/java/com/ycl/common/utils/excel/service/DictService.java new file mode 100644 index 0000000..801189e --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/service/DictService.java @@ -0,0 +1,67 @@ +package com.ycl.common.utils.excel.service; + +import java.util.Map; + +/** + * 閫氱敤 瀛楀吀鏈嶅姟 + * + * @author Lion Li + */ +public interface DictService { + + /** + * 鍒嗛殧绗� + */ + String SEPARATOR = ","; + + /** + * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏稿�艰幏鍙栧瓧鍏告爣绛� + * + * @param dictType 瀛楀吀绫诲瀷 + * @param dictValue 瀛楀吀鍊� + * @return 瀛楀吀鏍囩 + */ + default String getDictLabel(String dictType, String dictValue) { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + + /** + * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏告爣绛捐幏鍙栧瓧鍏稿�� + * + * @param dictType 瀛楀吀绫诲瀷 + * @param dictLabel 瀛楀吀鏍囩 + * @return 瀛楀吀鍊� + */ + default String getDictValue(String dictType, String dictLabel) { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + + /** + * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏稿�艰幏鍙栧瓧鍏告爣绛� + * + * @param dictType 瀛楀吀绫诲瀷 + * @param dictValue 瀛楀吀鍊� + * @param separator 鍒嗛殧绗� + * @return 瀛楀吀鏍囩 + */ + String getDictLabel(String dictType, String dictValue, String separator); + + /** + * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏告爣绛捐幏鍙栧瓧鍏稿�� + * + * @param dictType 瀛楀吀绫诲瀷 + * @param dictLabel 瀛楀吀鏍囩 + * @param separator 鍒嗛殧绗� + * @return 瀛楀吀鍊� + */ + String getDictValue(String dictType, String dictLabel, String separator); + + /** + * 鑾峰彇瀛楀吀涓嬫墍鏈夌殑瀛楀吀鍊间笌鏍囩 + * + * @param dictType 瀛楀吀绫诲瀷 + * @return dictValue涓簁ey锛宒ictLabel涓哄�肩粍鎴愮殑Map + */ + Map<String, String> getAllDictByDictType(String dictType); + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/utils/JsonUtils.java b/common/src/main/java/com/ycl/common/utils/excel/utils/JsonUtils.java new file mode 100644 index 0000000..3303c55 --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/utils/JsonUtils.java @@ -0,0 +1,169 @@ +package com.ycl.common.utils.excel.utils; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.ycl.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * JSON 宸ュ叿绫� + * + * @author 鑺嬮亾婧愮爜 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class JsonUtils { + + private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class); + + public static ObjectMapper getObjectMapper() { + return OBJECT_MAPPER; + } + + /** + * 灏嗗璞¤浆鎹负JSON鏍煎紡鐨勫瓧绗︿覆 + * + * @param object 瑕佽浆鎹㈢殑瀵硅薄 + * @return JSON鏍煎紡鐨勫瓧绗︿覆锛屽鏋滃璞′负null锛屽垯杩斿洖null + * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烰SON澶勭悊寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯� + */ + public static String toJsonString(Object object) { + if (ObjectUtil.isNull(object)) { + return null; + } + try { + return OBJECT_MAPPER.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + /** + * 灏咼SON鏍煎紡鐨勫瓧绗︿覆杞崲涓烘寚瀹氱被鍨嬬殑瀵硅薄 + * + * @param text JSON鏍煎紡鐨勫瓧绗︿覆 + * @param clazz 瑕佽浆鎹㈢殑鐩爣瀵硅薄绫诲瀷 + * @param <T> 鐩爣瀵硅薄鐨勬硾鍨嬬被鍨� + * @return 杞崲鍚庣殑瀵硅薄锛屽鏋滃瓧绗︿覆涓虹┖鍒欒繑鍥瀗ull + * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯� + */ + public static <T> T parseObject(String text, Class<T> clazz) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 灏嗗瓧鑺傛暟缁勮浆鎹负鎸囧畾绫诲瀷鐨勫璞� + * + * @param bytes 瀛楄妭鏁扮粍 + * @param clazz 瑕佽浆鎹㈢殑鐩爣瀵硅薄绫诲瀷 + * @param <T> 鐩爣瀵硅薄鐨勬硾鍨嬬被鍨� + * @return 杞崲鍚庣殑瀵硅薄锛屽鏋滃瓧鑺傛暟缁勪负绌哄垯杩斿洖null + * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯� + */ + public static <T> T parseObject(byte[] bytes, Class<T> clazz) { + if (ArrayUtil.isEmpty(bytes)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(bytes, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 灏咼SON鏍煎紡鐨勫瓧绗︿覆杞崲涓烘寚瀹氱被鍨嬬殑瀵硅薄锛屾敮鎸佸鏉傜被鍨� + * + * @param text JSON鏍煎紡鐨勫瓧绗︿覆 + * @param typeReference 鎸囧畾绫诲瀷鐨凾ypeReference瀵硅薄 + * @param <T> 鐩爣瀵硅薄鐨勬硾鍨嬬被鍨� + * @return 杞崲鍚庣殑瀵硅薄锛屽鏋滃瓧绗︿覆涓虹┖鍒欒繑鍥瀗ull + * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯� + */ + public static <T> T parseObject(String text, TypeReference<T> typeReference) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, typeReference); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 灏咼SON鏍煎紡鐨勫瓧绗︿覆杞崲涓篋ict瀵硅薄 + * + * @param text JSON鏍煎紡鐨勫瓧绗︿覆 + * @return 杞崲鍚庣殑Dict瀵硅薄锛屽鏋滃瓧绗︿覆涓虹┖鎴栬�呬笉鏄疛SON鏍煎紡鍒欒繑鍥瀗ull + * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯� + */ + public static Dict parseMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class)); + } catch (MismatchedInputException e) { + // 绫诲瀷涓嶅尮閰嶈鏄庝笉鏄痡son + return null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 灏咼SON鏍煎紡鐨勫瓧绗︿覆杞崲涓篋ict瀵硅薄鐨勫垪琛� + * + * @param text JSON鏍煎紡鐨勫瓧绗︿覆 + * @return 杞崲鍚庣殑Dict瀵硅薄鐨勫垪琛紝濡傛灉瀛楃涓蹭负绌哄垯杩斿洖null + * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯� + */ + public static List<Dict> parseArrayMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 灏咼SON鏍煎紡鐨勫瓧绗︿覆杞崲涓烘寚瀹氱被鍨嬪璞$殑鍒楄〃 + * + * @param text JSON鏍煎紡鐨勫瓧绗︿覆 + * @param clazz 瑕佽浆鎹㈢殑鐩爣瀵硅薄绫诲瀷 + * @param <T> 鐩爣瀵硅薄鐨勬硾鍨嬬被鍨� + * @return 杞崲鍚庣殑瀵硅薄鐨勫垪琛紝濡傛灉瀛楃涓蹭负绌哄垯杩斿洖绌哄垪琛� + * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯� + */ + public static <T> List<T> parseArray(String text, Class<T> clazz) { + if (StringUtils.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/utils/ReflectUtils.java b/common/src/main/java/com/ycl/common/utils/excel/utils/ReflectUtils.java new file mode 100644 index 0000000..c6bcfa9 --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/utils/ReflectUtils.java @@ -0,0 +1,55 @@ +package com.ycl.common.utils.excel.utils; + +import cn.hutool.core.util.ReflectUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.lang.reflect.Method; + +/** + * 鍙嶅皠宸ュ叿绫�. 鎻愪緵璋冪敤getter/setter鏂规硶, 璁块棶绉佹湁鍙橀噺, 璋冪敤绉佹湁鏂规硶, 鑾峰彇娉涘瀷绫诲瀷Class, 琚獳OP杩囩殑鐪熷疄绫荤瓑宸ュ叿鍑芥暟. + * + * @author Lion Li + */ +@SuppressWarnings("rawtypes") +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ReflectUtils extends ReflectUtil { + + private static final String SETTER_PREFIX = "set"; + + private static final String GETTER_PREFIX = "get"; + + /** + * 璋冪敤Getter鏂规硶. + * 鏀寔澶氱骇锛屽锛氬璞″悕.瀵硅薄鍚�.鏂规硶 + */ + @SuppressWarnings("unchecked") + public static <E> E invokeGetter(Object obj, String propertyName) { + Object object = obj; + for (String name : StringUtils.split(propertyName, ".")) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); + object = invoke(object, getterMethodName); + } + return (E) object; + } + + /** + * 璋冪敤Setter鏂规硶, 浠呭尮閰嶆柟娉曞悕銆� + * 鏀寔澶氱骇锛屽锛氬璞″悕.瀵硅薄鍚�.鏂规硶 + */ + public static <E> void invokeSetter(Object obj, String propertyName, E value) { + Object object = obj; + String[] names = StringUtils.split(propertyName, "."); + for (int i = 0; i < names.length; i++) { + if (i < names.length - 1) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); + object = invoke(object, getterMethodName); + } else { + String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); + Method method = getMethodByName(object.getClass(), setterMethodName); + invoke(object, method, value); + } + } + } + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/utils/StreamUtils.java b/common/src/main/java/com/ycl/common/utils/excel/utils/StreamUtils.java new file mode 100644 index 0000000..968774f --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/utils/StreamUtils.java @@ -0,0 +1,282 @@ +package com.ycl.common.utils.excel.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * stream 娴佸伐鍏风被 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class StreamUtils { + + /** + * 灏哻ollection杩囨护 + * + * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎 + * @param function 杩囨护鏂规硶 + * @return 杩囨护鍚庣殑list + */ + public static <E> List<E> filter(Collection<E> collection, Predicate<E> function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + // 娉ㄦ剰姝ゅ涓嶈浣跨敤 .toList() 鏂拌娉� 鍥犱负杩斿洖鐨勬槸涓嶅彲鍙楲ist 浼氬鑷村簭鍒楀寲闂 + return collection.stream().filter(function).collect(Collectors.toList()); + } + + /** + * 鎵惧埌娴佷腑婊¤冻鏉′欢鐨勭涓�涓厓绱� + * + * @param collection 闇�瑕佹煡璇㈢殑闆嗗悎 + * @param function 杩囨护鏂规硶 + * @return 鎵惧埌绗﹀悎鏉′欢鐨勭涓�涓厓绱狅紝娌℃湁鍒欒繑鍥瀗ull + */ + public static <E> E findFirst(Collection<E> collection, Predicate<E> function) { + if (CollUtil.isEmpty(collection)) { + return null; + } + return collection.stream().filter(function).findFirst().orElse(null); + } + + /** + * 鎵惧埌娴佷腑浠绘剰涓�涓弧瓒虫潯浠剁殑鍏冪礌 + * + * @param collection 闇�瑕佹煡璇㈢殑闆嗗悎 + * @param function 杩囨护鏂规硶 + * @return 鎵惧埌绗﹀悎鏉′欢鐨勪换鎰忎竴涓厓绱狅紝娌℃湁鍒欒繑鍥瀗ull + */ + public static <E> Optional<E> findAny(Collection<E> collection, Predicate<E> function) { + if (CollUtil.isEmpty(collection)) { + return Optional.empty(); + } + return collection.stream().filter(function).findAny(); + } + + /** + * 灏哻ollection鎷兼帴 + * + * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎 + * @param function 鎷兼帴鏂规硶 + * @return 鎷兼帴鍚庣殑list + */ + public static <E> String join(Collection<E> collection, Function<E, String> function) { + return join(collection, function, StringUtils.SEPARATOR); + } + + /** + * 灏哻ollection鎷兼帴 + * + * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎 + * @param function 鎷兼帴鏂规硶 + * @param delimiter 鎷兼帴绗� + * @return 鎷兼帴鍚庣殑list + */ + public static <E> String join(Collection<E> collection, Function<E, String> function, CharSequence delimiter) { + if (CollUtil.isEmpty(collection)) { + return StringUtils.EMPTY; + } + return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter)); + } + + /** + * 灏哻ollection鎺掑簭 + * + * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎 + * @param comparing 鎺掑簭鏂规硶 + * @return 鎺掑簭鍚庣殑list + */ + public static <E> List<E> sorted(Collection<E> collection, Comparator<E> comparing) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + // 娉ㄦ剰姝ゅ涓嶈浣跨敤 .toList() 鏂拌娉� 鍥犱负杩斿洖鐨勬槸涓嶅彲鍙楲ist 浼氬鑷村簭鍒楀寲闂 + return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList()); + } + + /** + * 灏哻ollection杞寲涓虹被鍨嬩笉鍙樼殑map<br> + * <B>{@code Collection<V> ----> Map<K,V>}</B> + * + * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎 + * @param key V绫诲瀷杞寲涓篕绫诲瀷鐨刲ambda鏂规硶 + * @param <V> collection涓殑娉涘瀷 + * @param <K> map涓殑key绫诲瀷 + * @return 杞寲鍚庣殑map + */ + public static <V, K> Map<K, V> toIdentityMap(Collection<V> collection, Function<V, K> key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, Function.identity(), (l, r) -> l)); + } + + /** + * 灏咰ollection杞寲涓簃ap(value绫诲瀷涓巆ollection鐨勬硾鍨嬩笉鍚�)<br> + * <B>{@code Collection<E> -----> Map<K,V> }</B> + * + * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎 + * @param key E绫诲瀷杞寲涓篕绫诲瀷鐨刲ambda鏂规硶 + * @param value E绫诲瀷杞寲涓篤绫诲瀷鐨刲ambda鏂规硶 + * @param <E> collection涓殑娉涘瀷 + * @param <K> map涓殑key绫诲瀷 + * @param <V> map涓殑value绫诲瀷 + * @return 杞寲鍚庣殑map + */ + public static <E, K, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> key, Function<E, V> value) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l)); + } + + /** + * 灏哻ollection鎸夌収瑙勫垯(姣斿鏈夌浉鍚岀殑鐝骇id)鍒嗙被鎴恗ap<br> + * <B>{@code Collection<E> -------> Map<K,List<E>> } </B> + * + * @param collection 闇�瑕佸垎绫荤殑闆嗗悎 + * @param key 鍒嗙被鐨勮鍒� + * @param <E> collection涓殑娉涘瀷 + * @param <K> map涓殑key绫诲瀷 + * @return 鍒嗙被鍚庣殑map + */ + public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList())); + } + + /** + * 灏哻ollection鎸夌収涓や釜瑙勫垯(姣斿鏈夌浉鍚岀殑骞寸骇id,鐝骇id)鍒嗙被鎴愬弻灞俶ap<br> + * <B>{@code Collection<E> ---> Map<T,Map<U,List<E>>> } </B> + * + * @param collection 闇�瑕佸垎绫荤殑闆嗗悎 + * @param key1 绗竴涓垎绫荤殑瑙勫垯 + * @param key2 绗簩涓垎绫荤殑瑙勫垯 + * @param <E> 闆嗗悎鍏冪礌绫诲瀷 + * @param <K> 绗竴涓猰ap涓殑key绫诲瀷 + * @param <U> 绗簩涓猰ap涓殑key绫诲瀷 + * @return 鍒嗙被鍚庣殑map + */ + public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1, Function<E, U> key2) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList()))); + } + + /** + * 灏哻ollection鎸夌収涓や釜瑙勫垯(姣斿鏈夌浉鍚岀殑骞寸骇id,鐝骇id)鍒嗙被鎴愬弻灞俶ap<br> + * <B>{@code Collection<E> ---> Map<T,Map<U,E>> } </B> + * + * @param collection 闇�瑕佸垎绫荤殑闆嗗悎 + * @param key1 绗竴涓垎绫荤殑瑙勫垯 + * @param key2 绗簩涓垎绫荤殑瑙勫垯 + * @param <T> 绗竴涓猰ap涓殑key绫诲瀷 + * @param <U> 绗簩涓猰ap涓殑key绫诲瀷 + * @param <E> collection涓殑娉涘瀷 + * @return 鍒嗙被鍚庣殑map + */ + public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1, Function<E, U> key2) { + if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l))); + } + + /** + * 灏哻ollection杞寲涓篖ist闆嗗悎锛屼絾鏄袱鑰呯殑娉涘瀷涓嶅悓<br> + * <B>{@code Collection<E> ------> List<T> } </B> + * + * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎 + * @param function collection涓殑娉涘瀷杞寲涓簂ist娉涘瀷鐨刲ambda琛ㄨ揪寮� + * @param <E> collection涓殑娉涘瀷 + * @param <T> List涓殑娉涘瀷 + * @return 杞寲鍚庣殑list + */ + public static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + // 娉ㄦ剰姝ゅ涓嶈浣跨敤 .toList() 鏂拌娉� 鍥犱负杩斿洖鐨勬槸涓嶅彲鍙楲ist 浼氬鑷村簭鍒楀寲闂 + .collect(Collectors.toList()); + } + + /** + * 灏哻ollection杞寲涓篠et闆嗗悎锛屼絾鏄袱鑰呯殑娉涘瀷涓嶅悓<br> + * <B>{@code Collection<E> ------> Set<T> } </B> + * + * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎 + * @param function collection涓殑娉涘瀷杞寲涓簊et娉涘瀷鐨刲ambda琛ㄨ揪寮� + * @param <E> collection涓殑娉涘瀷 + * @param <T> Set涓殑娉涘瀷 + * @return 杞寲鍚庣殑Set + */ + public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) { + if (CollUtil.isEmpty(collection) || function == null) { + return CollUtil.newHashSet(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + + /** + * 鍚堝苟涓や釜鐩稿悓key绫诲瀷鐨刴ap + * + * @param map1 绗竴涓渶瑕佸悎骞剁殑 map + * @param map2 绗簩涓渶瑕佸悎骞剁殑 map + * @param merge 鍚堝苟鐨刲ambda锛屽皢key value1 value2鍚堝苟鎴愭渶缁堢殑绫诲瀷,娉ㄦ剰value鍙兘涓虹┖鐨勬儏鍐� + * @param <K> map涓殑key绫诲瀷 + * @param <X> 绗竴涓� map鐨剉alue绫诲瀷 + * @param <Y> 绗簩涓� map鐨剉alue绫诲瀷 + * @param <V> 鏈�缁坢ap鐨剉alue绫诲瀷 + * @return 鍚堝苟鍚庣殑map + */ + public static <K, X, Y, V> Map<K, V> merge(Map<K, X> map1, Map<K, Y> map2, BiFunction<X, Y, V> merge) { + if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) { + return MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map1)) { + map1 = MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map2)) { + map2 = MapUtil.newHashMap(); + } + Set<K> key = new HashSet<>(); + key.addAll(map1.keySet()); + key.addAll(map2.keySet()); + Map<K, V> map = new HashMap<>(); + for (K t : key) { + X x = map1.get(t); + Y y = map2.get(t); + V z = merge.apply(x, y); + if (z != null) { + map.put(t, z); + } + } + return map; + } + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/utils/StringUtils.java b/common/src/main/java/com/ycl/common/utils/excel/utils/StringUtils.java new file mode 100644 index 0000000..8cf75f8 --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/utils/StringUtils.java @@ -0,0 +1,323 @@ +package com.ycl.common.utils.excel.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.StrUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.util.AntPathMatcher; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 瀛楃涓插伐鍏风被 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class StringUtils extends org.apache.commons.lang3.StringUtils { + + public static final String SEPARATOR = ","; + + public static final String SLASH = "/"; + + /** + * 鑾峰彇鍙傛暟涓嶄负绌哄�� + * + * @param str defaultValue 瑕佸垽鏂殑value + * @return value 杩斿洖鍊� + */ + public static String blankToDefault(String str, String defaultValue) { + return StrUtil.blankToDefault(str, defaultValue); + } + + /** + * * 鍒ゆ柇涓�涓瓧绗︿覆鏄惁涓虹┖涓� + * + * @param str String + * @return true锛氫负绌� false锛氶潪绌� + */ + public static boolean isEmpty(String str) { + return StrUtil.isEmpty(str); + } + + /** + * * 鍒ゆ柇涓�涓瓧绗︿覆鏄惁涓洪潪绌轰覆 + * + * @param str String + * @return true锛氶潪绌轰覆 false锛氱┖涓� + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * 鍘荤┖鏍� + */ + public static String trim(String str) { + return StrUtil.trim(str); + } + + /** + * 鎴彇瀛楃涓� + * + * @param str 瀛楃涓� + * @param start 寮�濮� + * @return 缁撴灉 + */ + public static String substring(final String str, int start) { + return substring(str, start, str.length()); + } + + /** + * 鎴彇瀛楃涓� + * + * @param str 瀛楃涓� + * @param start 寮�濮� + * @param end 缁撴潫 + * @return 缁撴灉 + */ + public static String substring(final String str, int start, int end) { + return StrUtil.sub(str, start, end); + } + + /** + * 鏍煎紡鍖栨枃鏈�, {} 琛ㄧず鍗犱綅绗�<br> + * 姝ゆ柟娉曞彧鏄畝鍗曞皢鍗犱綅绗� {} 鎸夌収椤哄簭鏇挎崲涓哄弬鏁�<br> + * 濡傛灉鎯宠緭鍑� {} 浣跨敤 \\杞箟 { 鍗冲彲锛屽鏋滄兂杈撳嚭 {} 涔嬪墠鐨� \ 浣跨敤鍙岃浆涔夌 \\\\ 鍗冲彲<br> + * 渚嬶細<br> + * 閫氬父浣跨敤锛歠ormat("this is {} for {}", "a", "b") -> this is a for b<br> + * 杞箟{}锛� format("this is \\{} for {}", "a", "b") -> this is {} for a<br> + * 杞箟\锛� format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br> + * + * @param template 鏂囨湰妯℃澘锛岃鏇挎崲鐨勯儴鍒嗙敤 {} 琛ㄧず + * @param params 鍙傛暟鍊� + * @return 鏍煎紡鍖栧悗鐨勬枃鏈� + */ + public static String format(String template, Object... params) { + return StrUtil.format(template, params); + } + + /** + * 鏄惁涓篽ttp(s)://寮�澶� + * + * @param link 閾炬帴 + * @return 缁撴灉 + */ + public static boolean ishttp(String link) { + return Validator.isUrl(link); + } + + /** + * 瀛楃涓茶浆set + * + * @param str 瀛楃涓� + * @param sep 鍒嗛殧绗� + * @return set闆嗗悎 + */ + public static Set<String> str2Set(String str, String sep) { + return new HashSet<>(str2List(str, sep, true, false)); + } + + /** + * 瀛楃涓茶浆list + * + * @param str 瀛楃涓� + * @param sep 鍒嗛殧绗� + * @param filterBlank 杩囨护绾┖鐧� + * @param trim 鍘绘帀棣栧熬绌虹櫧 + * @return list闆嗗悎 + */ + public static List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) { + List<String> list = new ArrayList<>(); + if (isEmpty(str)) { + return list; + } + + // 杩囨护绌虹櫧瀛楃涓� + if (filterBlank && isBlank(str)) { + return list; + } + String[] split = str.split(sep); + for (String string : split) { + if (filterBlank && isBlank(string)) { + continue; + } + if (trim) { + string = trim(string); + } + list.add(string); + } + + return list; + } + + /** + * 鏌ユ壘鎸囧畾瀛楃涓叉槸鍚﹀寘鍚寚瀹氬瓧绗︿覆鍒楄〃涓殑浠绘剰涓�涓瓧绗︿覆鍚屾椂涓插拷鐣ュぇ灏忓啓 + * + * @param cs 鎸囧畾瀛楃涓� + * @param searchCharSequences 闇�瑕佹鏌ョ殑瀛楃涓叉暟缁� + * @return 鏄惁鍖呭惈浠绘剰涓�涓瓧绗︿覆 + */ + public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) { + return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences); + } + + /** + * 椹煎嘲杞笅鍒掔嚎鍛藉悕 + */ + public static String toUnderScoreCase(String str) { + return StrUtil.toUnderlineCase(str); + } + + /** + * 鏄惁鍖呭惈瀛楃涓� + * + * @param str 楠岃瘉瀛楃涓� + * @param strs 瀛楃涓茬粍 + * @return 鍖呭惈杩斿洖true + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + return StrUtil.equalsAnyIgnoreCase(str, strs); + } + + /** + * 灏嗕笅鍒掔嚎澶у啓鏂瑰紡鍛藉悕鐨勫瓧绗︿覆杞崲涓洪┘宄板紡銆傚鏋滆浆鎹㈠墠鐨勪笅鍒掔嚎澶у啓鏂瑰紡鍛藉悕鐨勫瓧绗︿覆涓虹┖锛屽垯杩斿洖绌哄瓧绗︿覆銆� 渚嬪锛欻ELLO_WORLD->HelloWorld + * + * @param name 杞崲鍓嶇殑涓嬪垝绾垮ぇ鍐欐柟寮忓懡鍚嶇殑瀛楃涓� + * @return 杞崲鍚庣殑椹煎嘲寮忓懡鍚嶇殑瀛楃涓� + */ + public static String convertToCamelCase(String name) { + return StrUtil.upperFirst(StrUtil.toCamelCase(name)); + } + + /** + * 椹煎嘲寮忓懡鍚嶆硶 渚嬪锛歶ser_name->userName + */ + public static String toCamelCase(String s) { + return StrUtil.toCamelCase(s); + } + + /** + * 鏌ユ壘鎸囧畾瀛楃涓叉槸鍚﹀尮閰嶆寚瀹氬瓧绗︿覆鍒楄〃涓殑浠绘剰涓�涓瓧绗︿覆 + * + * @param str 鎸囧畾瀛楃涓� + * @param strs 闇�瑕佹鏌ョ殑瀛楃涓叉暟缁� + * @return 鏄惁鍖归厤 + */ + public static boolean matches(String str, List<String> strs) { + if (isEmpty(str) || CollUtil.isEmpty(strs)) { + return false; + } + for (String pattern : strs) { + if (isMatch(pattern, str)) { + return true; + } + } + return false; + } + + /** + * 鍒ゆ柇url鏄惁涓庤鍒欓厤缃�: + * ? 琛ㄧず鍗曚釜瀛楃; + * * 琛ㄧず涓�灞傝矾寰勫唴鐨勪换鎰忓瓧绗︿覆锛屼笉鍙法灞傜骇; + * ** 琛ㄧず浠绘剰灞傝矾寰�; + * + * @param pattern 鍖归厤瑙勫垯 + * @param url 闇�瑕佸尮閰嶇殑url + */ + public static boolean isMatch(String pattern, String url) { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + + /** + * 鏁板瓧宸﹁竟琛ラ綈0锛屼娇涔嬭揪鍒版寚瀹氶暱搴︺�傛敞鎰忥紝濡傛灉鏁板瓧杞崲涓哄瓧绗︿覆鍚庯紝闀垮害澶т簬size锛屽垯鍙繚鐣� 鏈�鍚巗ize涓瓧绗︺�� + * + * @param num 鏁板瓧瀵硅薄 + * @param size 瀛楃涓叉寚瀹氶暱搴� + * @return 杩斿洖鏁板瓧鐨勫瓧绗︿覆鏍煎紡锛岃瀛楃涓蹭负鎸囧畾闀垮害銆� + */ + public static String padl(final Number num, final int size) { + return padl(num.toString(), size, '0'); + } + + /** + * 瀛楃涓插乏琛ラ綈銆傚鏋滃師濮嬪瓧绗︿覆s闀垮害澶т簬size锛屽垯鍙繚鐣欐渶鍚巗ize涓瓧绗︺�� + * + * @param s 鍘熷瀛楃涓� + * @param size 瀛楃涓叉寚瀹氶暱搴� + * @param c 鐢ㄤ簬琛ラ綈鐨勫瓧绗� + * @return 杩斿洖鎸囧畾闀垮害鐨勫瓧绗︿覆锛岀敱鍘熷瓧绗︿覆宸﹁ˉ榻愭垨鎴彇寰楀埌銆� + */ + public static String padl(final String s, final int size, final char c) { + final StringBuilder sb = new StringBuilder(size); + if (s != null) { + final int len = s.length(); + if (s.length() <= size) { + sb.append(String.valueOf(c).repeat(size - len)); + sb.append(s); + } else { + return s.substring(len - size, len); + } + } else { + sb.append(String.valueOf(c).repeat(Math.max(0, size))); + } + return sb.toString(); + } + + /** + * 鍒囧垎瀛楃涓�(鍒嗛殧绗﹂粯璁ら�楀彿) + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @return 鍒嗗壊鍚庣殑鏁版嵁鍒楄〃 + */ + public static List<String> splitList(String str) { + return splitTo(str, Convert::toStr); + } + + /** + * 鍒囧垎瀛楃涓� + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param separator 鍒嗛殧绗� + * @return 鍒嗗壊鍚庣殑鏁版嵁鍒楄〃 + */ + public static List<String> splitList(String str, String separator) { + return splitTo(str, separator, Convert::toStr); + } + + /** + * 鍒囧垎瀛楃涓茶嚜瀹氫箟杞崲(鍒嗛殧绗﹂粯璁ら�楀彿) + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param mapper 鑷畾涔夎浆鎹� + * @return 鍒嗗壊鍚庣殑鏁版嵁鍒楄〃 + */ + public static <T> List<T> splitTo(String str, Function<? super Object, T> mapper) { + return splitTo(str, SEPARATOR, mapper); + } + + /** + * 鍒囧垎瀛楃涓茶嚜瀹氫箟杞崲 + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param separator 鍒嗛殧绗� + * @param mapper 鑷畾涔夎浆鎹� + * @return 鍒嗗壊鍚庣殑鏁版嵁鍒楄〃 + */ + public static <T> List<T> splitTo(String str, String separator, Function<? super Object, T> mapper) { + if (isBlank(str)) { + return new ArrayList<>(0); + } + return StrUtil.split(str, separator) + .stream() + .filter(Objects::nonNull) + .map(mapper) + .collect(Collectors.toList()); + } + +} diff --git a/common/src/main/java/com/ycl/common/utils/excel/utils/ValidatorUtils.java b/common/src/main/java/com/ycl/common/utils/excel/utils/ValidatorUtils.java new file mode 100644 index 0000000..9ac6f62 --- /dev/null +++ b/common/src/main/java/com/ycl/common/utils/excel/utils/ValidatorUtils.java @@ -0,0 +1,36 @@ +package com.ycl.common.utils.excel.utils; + +import com.ycl.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validator; +import java.util.Set; + +/** + * Validator 鏍¢獙妗嗘灦宸ュ叿 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ValidatorUtils { + + private static final Validator VALID = SpringUtils.getBean(Validator.class); + + /** + * 瀵圭粰瀹氬璞¤繘琛屽弬鏁版牎楠岋紝骞舵牴鎹寚瀹氱殑鏍¢獙缁勮繘琛屾牎楠� + * + * @param object 瑕佽繘琛屾牎楠岀殑瀵硅薄 + * @param groups 鏍¢獙缁� + * @throws ConstraintViolationException 濡傛灉鏍¢獙涓嶉�氳繃锛屽垯鎶涘嚭鍙傛暟鏍¢獙寮傚父 + */ + public static <T> void validate(T object, Class<?>... groups) { + Set<ConstraintViolation<T>> validate = VALID.validate(object, groups); + if (!validate.isEmpty()) { + throw new ConstraintViolationException("鍙傛暟鏍¢獙寮傚父", validate); + } + } + +} diff --git a/system/pom.xml b/system/pom.xml index 18ddae0..1482ed7 100644 --- a/system/pom.xml +++ b/system/pom.xml @@ -22,12 +22,6 @@ <artifactId>knife4j-spring-boot-starter</artifactId> </dependency> - <!-- easy excel --> - <dependency> - <groupId>com.alibaba</groupId> - <artifactId>easyexcel</artifactId> - </dependency> - <!-- 楠岃瘉鐮� --> <dependency> -- Gitblit v1.8.0