From 056c9d60e9d5355fc45f644dcce289a1a6ce2d9d Mon Sep 17 00:00:00 2001 From: "xiaodong.hu" <1075471126@qq.com> Date: Mon, 14 Aug 2023 13:31:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=BA=BF=E7=B4=A2=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E4=B8=8E=E6=96=B0=E5=A2=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/cool/store/annotation/Excel.java | 169 +++ .../com/cool/store/annotation/Excels.java | 18 + .../store/constants/ExcelErrorConstants.java | 28 + .../store/enums/AcceptAdjustTypeEnum.java | 26 + .../com/cool/store/enums/ErrorCodeEnum.java | 1 + .../com/cool/store/dao/EnterpriseUserDAO.java | 8 + .../com/cool/store/dao/HyOpenAreaInfoDAO.java | 8 + .../store/mapper/EnterpriseUserMapper.java | 2 + .../store/mapper/HyOpenAreaInfoMapper.java | 2 + .../resources/mapper/EnterpriseUserMapper.xml | 5 + .../resources/mapper/HyOpenAreaInfoMapper.xml | 6 + .../cool/store/entity/HyPartnerLineDO.java | 63 + .../cool/store/request/AddLineRequest.java | 51 + .../response/error/ErrorExcelResponse.java | 27 + coolstore-partner-service/pom.xml | 9 + .../store/service/LineHighSeasService.java | 12 + .../service/impl/LineHighSeasServiceImpl.java | 239 ++++ .../com/cool/store/utils/poi/DateUtils.java | 223 ++++ .../com/cool/store/utils/poi/ExcelUtil.java | 1153 +++++++++++++++++ .../com/cool/store/utils/poi/StringUtils.java | 522 ++++++++ .../store/utils/poi/constant/Constants.java | 166 +++ .../store/utils/poi/reflect/ReflectUtils.java | 403 ++++++ .../cool/store/utils/poi/text/Convert.java | 998 ++++++++++++++ .../controller/LineHighSeasController.java | 48 + pom.xml | 11 + 25 files changed, 4198 insertions(+) create mode 100644 coolstore-partner-common/src/main/java/com/cool/store/annotation/Excel.java create mode 100644 coolstore-partner-common/src/main/java/com/cool/store/annotation/Excels.java create mode 100644 coolstore-partner-common/src/main/java/com/cool/store/constants/ExcelErrorConstants.java create mode 100644 coolstore-partner-model/src/main/java/com/cool/store/entity/HyPartnerLineDO.java create mode 100644 coolstore-partner-model/src/main/java/com/cool/store/request/AddLineRequest.java create mode 100644 coolstore-partner-model/src/main/java/com/cool/store/response/error/ErrorExcelResponse.java create mode 100644 coolstore-partner-service/src/main/java/com/cool/store/service/LineHighSeasService.java create mode 100644 coolstore-partner-service/src/main/java/com/cool/store/service/impl/LineHighSeasServiceImpl.java create mode 100644 coolstore-partner-service/src/main/java/com/cool/store/utils/poi/DateUtils.java create mode 100644 coolstore-partner-service/src/main/java/com/cool/store/utils/poi/ExcelUtil.java create mode 100644 coolstore-partner-service/src/main/java/com/cool/store/utils/poi/StringUtils.java create mode 100644 coolstore-partner-service/src/main/java/com/cool/store/utils/poi/constant/Constants.java create mode 100644 coolstore-partner-service/src/main/java/com/cool/store/utils/poi/reflect/ReflectUtils.java create mode 100644 coolstore-partner-service/src/main/java/com/cool/store/utils/poi/text/Convert.java create mode 100644 coolstore-partner-webb/src/main/java/com/cool/store/controller/LineHighSeasController.java diff --git a/coolstore-partner-common/src/main/java/com/cool/store/annotation/Excel.java b/coolstore-partner-common/src/main/java/com/cool/store/annotation/Excel.java new file mode 100644 index 000000000..1b8d4970a --- /dev/null +++ b/coolstore-partner-common/src/main/java/com/cool/store/annotation/Excel.java @@ -0,0 +1,169 @@ +package com.cool.store.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.math.BigDecimal; + +/** + * 自定义导出Excel数据注解 + * + * @author ruoyi + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Excel +{ + /** + * 导出时在excel中排序 + */ + int sort() default Integer.MAX_VALUE; + + /** + * 导出到Excel中的名字. + */ + String name() default ""; + + /** + * 日期格式, 如: yyyy-MM-dd + */ + String dateFormat() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + String readConverterExp() default ""; + + /** + * 分隔符,读取字符串组内容 + */ + String separator() default ","; + + /** + * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化) + */ + int scale() default -1; + + /** + * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN + */ + int roundingMode() default BigDecimal.ROUND_HALF_EVEN; + + /** + * 导出类型(0数字 1字符串) + */ + ColumnType cellType() default ColumnType.STRING; + + /** + * 导出时在excel中每个列的高度 单位为字符 + */ + double height() default 14; + + /** + * 导出时在excel中每个列的宽 单位为字符 + */ + double width() default 16; + + /** + * 文字后缀,如% 90 变成90% + */ + String suffix() default ""; + + /** + * 当值为空时,字段的默认值 + */ + String defaultValue() default ""; + + /** + * 提示信息 + */ + String prompt() default ""; + + /** + * 设置只能选择不能输入的列内容. + */ + String[] combo() default {}; + + /** + * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写. + */ + boolean isExport() default true; + + /** + * 另一个类中的属性名称,支持多级获取,以小数点隔开 + */ + String targetAttr() default ""; + + /** + * 是否自动统计数据,在最后追加一行统计数据总和 + */ + boolean isStatistics() default false; + /** + * 列颜色(列头与列内容) IndexedColors.SKY_BLUE.getIndex() + */ + short columnsColor() default 0; + + /** + * 须比较列 注解所在列顺序与比较列属性的值进行比较 + */ + String compareColName() default ""; + /** + * 导出错误信息 + */ + String compareExportInfo() default ""; + /** + * 字段类型(0:导出导入;1:仅导出;2:仅导入) + */ + Type type() default Type.ALL; + + enum Type + { + /** + * 导出导入 + */ + ALL(0), + /** + * 仅导出 + */ + EXPORT(1), + /** + * 仅导入 + */ + IMPORT(2); + private final int value; + + Type(int value) + { + this.value = value; + } + + public int value() + { + return this.value; + } + } + + enum ColumnType + { + /** + * 数字 + */ + NUMERIC(0), + /** + * 字符串 + */ + STRING(1); + private final int value; + + ColumnType(int value) + { + this.value = value; + } + + public int value() + { + return this.value; + } + } +} diff --git a/coolstore-partner-common/src/main/java/com/cool/store/annotation/Excels.java b/coolstore-partner-common/src/main/java/com/cool/store/annotation/Excels.java new file mode 100644 index 000000000..a1c7c6e0d --- /dev/null +++ b/coolstore-partner-common/src/main/java/com/cool/store/annotation/Excels.java @@ -0,0 +1,18 @@ +package com.cool.store.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Excel注解集 + * + * @author ruoyi + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Excels +{ + Excel[] value(); +} diff --git a/coolstore-partner-common/src/main/java/com/cool/store/constants/ExcelErrorConstants.java b/coolstore-partner-common/src/main/java/com/cool/store/constants/ExcelErrorConstants.java new file mode 100644 index 000000000..046477b12 --- /dev/null +++ b/coolstore-partner-common/src/main/java/com/cool/store/constants/ExcelErrorConstants.java @@ -0,0 +1,28 @@ +package com.cool.store.constants; + +/** + * hxd + */ +public class ExcelErrorConstants { + + public static final String NAME_LOSE = "姓名缺失"; + + public static final String MOBILE_LOSE= "手机号缺失"; + + public static final String MOBILE_ERROR= "手机号有误"; + + public static final String MOBILE_EXIST= "手机号已存在"; + + public static final String LIVEAREA_LOSE= "常驻区域缺失"; + + public static final String LIVEAREA_FORMAT_ERROR= "常驻区域格式错误"; + + public static final String WANTSHOPAREA_LOSE= "意向区域缺失"; + + public static final String WANTSHOPAREA_FORMAT_ERROR= "意向区域格式错误"; + + public static final String ACCEPTADJUSTTYPE_LOSE= "是否接受调剂缺失"; + + public static final String INVESTMENTMANAGER_LOSE= "未找到此招商经理,请核实"; + +} diff --git a/coolstore-partner-common/src/main/java/com/cool/store/enums/AcceptAdjustTypeEnum.java b/coolstore-partner-common/src/main/java/com/cool/store/enums/AcceptAdjustTypeEnum.java index 20ad79fb7..58ea23597 100644 --- a/coolstore-partner-common/src/main/java/com/cool/store/enums/AcceptAdjustTypeEnum.java +++ b/coolstore-partner-common/src/main/java/com/cool/store/enums/AcceptAdjustTypeEnum.java @@ -34,4 +34,30 @@ public enum AcceptAdjustTypeEnum { public String getMessage() { return message; } + + + public String getMessage(String enums) { + return AcceptAdjustTypeEnum.valueOf(enums).getMessage(); + } + + + public Integer getCode(String enums) { + return AcceptAdjustTypeEnum.valueOf(enums).getCode(); + } + + + /** + * 根据name查找 + * @param message 枚举message + * @return 枚举对象 + */ + public static Integer findEnumByName(String message) { + for (AcceptAdjustTypeEnum statusEnum : AcceptAdjustTypeEnum.values()) { + if (statusEnum.getMessage().equals(message)) { + //如果需要直接返回code则更改返回类型为String,return statusEnum.code; + return statusEnum.getCode(); + } + } + return null; + } } diff --git a/coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java b/coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java index 69ec9e182..71c763765 100644 --- a/coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java +++ b/coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java @@ -61,6 +61,7 @@ public enum ErrorCodeEnum { INTENT_AREA_NOT_BING_ZONE(500007, "意向区域没有绑定战区 分配招商经理失败!", null), PUBLIC_LINE_NOT_OPERATE(500008, "公海线索不允许操作!", null), PARTNER_BASE_INFO_NOT_EXIST(500009, "加盟商信息不存在!", null), + PARTNER_MOBILE_EXIST(500010, "手机号码已存在,请核实!", null), INTERVIEW_ENTER_FAIL(1021101, "进入面试间失败", null), DINGDING_USER_NOT_EXIST(1021102, "用户钉钉信息不存在,无法发起资质审核!", null), diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/dao/EnterpriseUserDAO.java b/coolstore-partner-dao/src/main/java/com/cool/store/dao/EnterpriseUserDAO.java index e78dd8326..bcc3c2400 100644 --- a/coolstore-partner-dao/src/main/java/com/cool/store/dao/EnterpriseUserDAO.java +++ b/coolstore-partner-dao/src/main/java/com/cool/store/dao/EnterpriseUserDAO.java @@ -3,6 +3,7 @@ package com.cool.store.dao; import com.cool.store.constants.CommonConstants; import com.cool.store.entity.EnterpriseUserDO; import com.cool.store.mapper.EnterpriseUserMapper; +import com.cool.store.utils.StringUtil; import com.google.common.collect.Lists; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -129,4 +130,11 @@ public class EnterpriseUserDAO { EnterpriseUserDO userInfo = getUserInfoById(userId); return Optional.ofNullable(userInfo).map(EnterpriseUserDO::getName).orElse(StringUtils.EMPTY); } + + public EnterpriseUserDO selectByInvestmentManager(String investmentManager) { + if (StringUtil.isEmpty(investmentManager)) { + return null; + } + return enterpriseUserMapper.selectByInvestmentManager(investmentManager); + } } \ No newline at end of file diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/dao/HyOpenAreaInfoDAO.java b/coolstore-partner-dao/src/main/java/com/cool/store/dao/HyOpenAreaInfoDAO.java index 0c344662b..9903efe42 100644 --- a/coolstore-partner-dao/src/main/java/com/cool/store/dao/HyOpenAreaInfoDAO.java +++ b/coolstore-partner-dao/src/main/java/com/cool/store/dao/HyOpenAreaInfoDAO.java @@ -5,6 +5,7 @@ import com.cool.store.dto.partner.ApplyReservationProvinceDTO; import com.cool.store.entity.HyOpenAreaInfoDO; import com.cool.store.entity.HyPartnerBaseInfoDO; import com.cool.store.mapper.HyOpenAreaInfoMapper; +import com.cool.store.utils.StringUtil; import com.github.pagehelper.PageInfo; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -148,4 +149,11 @@ public class HyOpenAreaInfoDAO { return provinceCodeList; } } + + public HyOpenAreaInfoDO selectByAreaPath(String areaPath) { + if (StringUtil.isEmpty(areaPath)) { + return null; + } + return hyOpenAreaInfoMapper.selectByAreaPath(areaPath); + } } diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/EnterpriseUserMapper.java b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/EnterpriseUserMapper.java index 99a688222..488949068 100644 --- a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/EnterpriseUserMapper.java +++ b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/EnterpriseUserMapper.java @@ -93,4 +93,6 @@ public interface EnterpriseUserMapper { String selectByMobile(@Param("mobile") String mobile); + EnterpriseUserDO selectByInvestmentManager(@Param("investmentManager") String investmentManager); + } \ No newline at end of file diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/HyOpenAreaInfoMapper.java b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/HyOpenAreaInfoMapper.java index 37d587c9a..c373f479b 100644 --- a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/HyOpenAreaInfoMapper.java +++ b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/HyOpenAreaInfoMapper.java @@ -121,4 +121,6 @@ public interface HyOpenAreaInfoMapper { List getSonArea(@Param("id") String id); List getProvinceAllCode(@Param("id") String id); + + HyOpenAreaInfoDO selectByAreaPath(@Param("areaPath") String areaPath); } \ No newline at end of file diff --git a/coolstore-partner-dao/src/main/resources/mapper/EnterpriseUserMapper.xml b/coolstore-partner-dao/src/main/resources/mapper/EnterpriseUserMapper.xml index cdb899eb4..54da90533 100644 --- a/coolstore-partner-dao/src/main/resources/mapper/EnterpriseUserMapper.xml +++ b/coolstore-partner-dao/src/main/resources/mapper/EnterpriseUserMapper.xml @@ -311,4 +311,9 @@ + \ No newline at end of file diff --git a/coolstore-partner-dao/src/main/resources/mapper/HyOpenAreaInfoMapper.xml b/coolstore-partner-dao/src/main/resources/mapper/HyOpenAreaInfoMapper.xml index 4bb44176d..60b212972 100644 --- a/coolstore-partner-dao/src/main/resources/mapper/HyOpenAreaInfoMapper.xml +++ b/coolstore-partner-dao/src/main/resources/mapper/HyOpenAreaInfoMapper.xml @@ -303,5 +303,11 @@ SELECT b.* FROM `hy_open_area_info` a inner join hy_open_area_info b on a.`id`=b.`parent_id` WHERE a.parent_id=#{id} ORDER BY b.id desc + \ No newline at end of file diff --git a/coolstore-partner-model/src/main/java/com/cool/store/entity/HyPartnerLineDO.java b/coolstore-partner-model/src/main/java/com/cool/store/entity/HyPartnerLineDO.java new file mode 100644 index 000000000..510a45373 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/entity/HyPartnerLineDO.java @@ -0,0 +1,63 @@ +package com.cool.store.entity; + +import com.cool.store.annotation.Excel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * + * @author hxd + * @date 2023-05-29 03:52 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class HyPartnerLineDO implements Serializable { + + @Excel(name = "*姓名(必填)") + @ApiModelProperty("姓名") + private String partnerName; + + @Excel(name = "*手机号(必填)") + @ApiModelProperty("手机号") + private String mobile; + + @Excel(name = "*常驻区域(必填)") + @ApiModelProperty("常驻区域") + private String liveAreaReplace; + + private String liveArea; + + @Excel(name = "*意向区域(必填)") + @ApiModelProperty("意向区域") + private String wantShopAreaReplace; + + private Long wantShopArea; + + @Excel(name = "*是否接受调剂(必填)") + @ApiModelProperty("是否接受调剂") + private String acceptAdjustTypeReplace; + + private Integer acceptAdjustType; + + @Excel(name = "分配招商经理") + @ApiModelProperty("分配招商经理") + private String investmentManagerReplace; + + private String investmentManager; + + + + @Excel(name = "错误信息") + @ApiModelProperty("错误信息") + private String errorInfo; + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/request/AddLineRequest.java b/coolstore-partner-model/src/main/java/com/cool/store/request/AddLineRequest.java new file mode 100644 index 000000000..6faa4e435 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/request/AddLineRequest.java @@ -0,0 +1,51 @@ +package com.cool.store.request; + + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; +import java.util.List; + +/** + * @Author hxd + * @Date 2023/5/31 11:19 + * @Version 1.0 + */ +@Data +@ApiModel +@Accessors(chain = true) +public class AddLineRequest { + + + @NotBlank(message = "姓名不能为空") + @ApiModelProperty("姓名") + private String partnerName; + + @Pattern(regexp = "(?:0|86|\\+86)?1[3-9]\\d{9}",message = "手机号码不正确,请检查后重试") + @ApiModelProperty("手机号") + private String mobile; + + @NotBlank(message = "常驻区域为空") + @ApiModelProperty("常驻区域") + private String liveArea; + + @NotBlank(message = "意向区域不能为空") + @ApiModelProperty("意向区域") + private String wantShopArea; + + + /** + * (0不接受调剂、1全国调剂、2省内调剂、3市内调剂)* + */ + @NotBlank(message = "是否接受调剂不能为空") + @ApiModelProperty("是否接受调剂") + private Integer acceptAdjustType; + + + @ApiModelProperty("分配招商经理") + private String investmentManager; +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/response/error/ErrorExcelResponse.java b/coolstore-partner-model/src/main/java/com/cool/store/response/error/ErrorExcelResponse.java new file mode 100644 index 000000000..4e4baf86a --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/response/error/ErrorExcelResponse.java @@ -0,0 +1,27 @@ +package com.cool.store.response.error; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * @author hxd + * @FileName: ErrorExcelResponse + * @Description: + * @date 2023-08-13 19:43 + */ +@Data +@Accessors(chain = true) +public class ErrorExcelResponse { + + private Integer total; + + private Integer errorNum; + + private String file; + + public ErrorExcelResponse(Integer total,Integer errorNum,String file){ + this.total=total; + this.errorNum=errorNum; + this.file=file; + } +} diff --git a/coolstore-partner-service/pom.xml b/coolstore-partner-service/pom.xml index 05dea92c7..c0087cedb 100644 --- a/coolstore-partner-service/pom.xml +++ b/coolstore-partner-service/pom.xml @@ -85,6 +85,15 @@ dysmsapi20170525 2.0.1 + + + com.alibaba + easyexcel + + + org.apache.poi + poi-ooxml + \ No newline at end of file diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/LineHighSeasService.java b/coolstore-partner-service/src/main/java/com/cool/store/service/LineHighSeasService.java new file mode 100644 index 000000000..d7cc60132 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/LineHighSeasService.java @@ -0,0 +1,12 @@ +package com.cool.store.service; + +import com.cool.store.request.AddLineRequest; +import com.cool.store.response.ResponseResult; +import org.springframework.web.multipart.MultipartFile; + +public interface LineHighSeasService { + + Boolean addLine(AddLineRequest request); + + ResponseResult importLine(MultipartFile file); +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/LineHighSeasServiceImpl.java b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/LineHighSeasServiceImpl.java new file mode 100644 index 000000000..4e22a6c42 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/LineHighSeasServiceImpl.java @@ -0,0 +1,239 @@ +package com.cool.store.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.cool.store.constants.ExcelErrorConstants; +import com.cool.store.dao.*; +import com.cool.store.entity.*; +import com.cool.store.enums.AcceptAdjustTypeEnum; +import com.cool.store.enums.ErrorCodeEnum; +import com.cool.store.enums.LineStatusEnum; +import com.cool.store.enums.WorkflowStatusEnum; +import com.cool.store.exception.ServiceException; +import com.cool.store.oss.OSSServer; +import com.cool.store.request.AddLineRequest; +import com.cool.store.response.ResponseResult; +import com.cool.store.response.error.ErrorExcelResponse; +import com.cool.store.service.HyPartnerLineInfoService; +import com.cool.store.service.LineHighSeasService; +import com.cool.store.utils.StringUtil; +import com.cool.store.utils.UUIDUtils; +import com.cool.store.utils.poi.ExcelUtil; +import com.cool.store.utils.poi.constant.Constants; +import lombok.SneakyThrows; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Service +public class LineHighSeasServiceImpl implements LineHighSeasService { + + + @Resource + private HyPartnerUserInfoDAO hyPartnerUserInfoDAO; + + @Resource + private EnterpriseUserDAO enterpriseUserDAO; + + @Resource + private HyOpenAreaInfoDAO hyOpenAreaInfoDAO; + + @Resource + private HyPartnerLineInfoDAO hyPartnerLineInfoDAO; + + @Resource + private HyPartnerBaseInfoDAO hyPartnerBaseInfoDAO; + + @Resource + HyPartnerLineInfoService hyPartnerLineInfoService; + + @Resource + private OSSServer ossServer; + + private final int excelMaxSize = 500; + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean addLine(AddLineRequest request) { + HyPartnerUserInfoDO hyPartnerUserInfoDO = hyPartnerUserInfoDAO.selectByMobile(request.getMobile()); + if (ObjectUtil.isNotNull(hyPartnerUserInfoDO)) { + throw new ServiceException(ErrorCodeEnum.PARTNER_MOBILE_EXIST); + } + add(request); + return Boolean.TRUE; + } + + + /** + * 新增线索 + * @param request + */ + public void add(AddLineRequest request) { + String partnerId = UUIDUtils.get32UUID(); + HyPartnerUserInfoDO resultUser = new HyPartnerUserInfoDO(); + resultUser.setUsername(request.getPartnerName()).setMobile(request.getMobile()).setPartnerId(partnerId).setCreateTime(new Date()).setAcceptAdjustType(request.getAcceptAdjustType()) + .setLiveArea(request.getLiveArea()).setWantShopArea(request.getWantShopArea()); + hyPartnerUserInfoDAO.insertSelective(resultUser); + + HyPartnerLineInfoDO resultLine = new HyPartnerLineInfoDO(); + resultLine.setPartnerId(partnerId).setCreateTime(new Date()); + + //判断招商经理是否为空 + if (StringUtil.isNotEmpty(request.getInvestmentManager())) { + resultLine.setInvestmentManager(request.getInvestmentManager()).setLineStatus(LineStatusEnum.PRIVATE_SEAS.getCode()); + } else { + //是否分配跟进人 + Boolean flag = hyPartnerLineInfoService.assignFollowUser(partnerId, request.getWantShopArea(), request.getAcceptAdjustType(), Boolean.TRUE); + if (flag) { + //查询跟进人 + String investmentManager = hyPartnerLineInfoService.getAssignFollowUser(partnerId, "intent"); + resultLine.setInvestmentManager(investmentManager).setLineStatus(LineStatusEnum.PRIVATE_SEAS.getCode()); + } else { + //直接放公海 + resultLine.setLineStatus(LineStatusEnum.PUBLIC_SEAS.getCode()); + } + } + hyPartnerLineInfoDAO.insertSelective(resultLine); + + HyPartnerBaseInfoDO resultBase = new HyPartnerBaseInfoDO(); + resultBase.setPartnerId(partnerId).setPartnerLineId(resultLine.getId()).setStatus(Integer.valueOf(WorkflowStatusEnum.INTENT_0.getCode())). + setCreateTime(new Date()).setUsername(request.getPartnerName()).setMobile(request.getMobile()); + hyPartnerBaseInfoDAO.insertSelective(resultBase); + + } + + @SneakyThrows + @Override + @Transactional(rollbackFor = Exception.class) + public ResponseResult importLine(MultipartFile file) { + ExcelUtil util = new ExcelUtil(HyPartnerLineDO.class); + List lineDOList = util.importExcel(file.getInputStream()); + if (lineDOList.size() > excelMaxSize) { + + //上传文件到oss +// ossServer.uploadFileServer() + return new ResponseResult(500, "", new ErrorExcelResponse(lineDOList.size(), excelMaxSize, "")); + } + Map>> styleCells = new HashMap<>(4); + for (int i = 0; i < lineDOList.size(); i++) { + HyPartnerLineDO hyPartnerLineDO = lineDOList.get(i); + if (StringUtil.isEmpty(hyPartnerLineDO.getPartnerName())) { + hyPartnerLineDO.setErrorInfo(hyPartnerLineDO.getErrorInfo().concat(Constants.SEMICOLON).concat(ExcelErrorConstants.NAME_LOSE)); + ExcelUtil.setStyleMap(styleCells, i, 1, new String[]{ExcelUtil.FONT_RED}); + } + String mobile = hyPartnerLineDO.getMobile(); + //手机号为空 + if (StringUtil.isEmpty(mobile)) { + hyPartnerLineDO.setErrorInfo(hyPartnerLineDO.getErrorInfo().concat(Constants.SEMICOLON).concat(ExcelErrorConstants.MOBILE_LOSE)); + ExcelUtil.setStyleMap(styleCells, i, 2, new String[]{ExcelUtil.FONT_RED}); + } else { + //手机号格式判断 + if (!isPhone(mobile)) { + hyPartnerLineDO.setErrorInfo(hyPartnerLineDO.getErrorInfo().concat(Constants.SEMICOLON).concat(ExcelErrorConstants.MOBILE_ERROR)); + ExcelUtil.setStyleMap(styleCells, i, 2, new String[]{ExcelUtil.FONT_RED}); + } + //手机号是否已存在 + HyPartnerUserInfoDO hyPartnerUserInfoDO = hyPartnerUserInfoDAO.selectByMobile(mobile); + if (ObjectUtil.isNotNull(hyPartnerUserInfoDO)) { + hyPartnerLineDO.setErrorInfo(hyPartnerLineDO.getErrorInfo().concat(Constants.SEMICOLON).concat(ExcelErrorConstants.MOBILE_EXIST)); + ExcelUtil.setStyleMap(styleCells, i, 2, new String[]{ExcelUtil.FONT_RED}); + } + } + //常驻区域为空 + String liveArea = hyPartnerLineDO.getLiveAreaReplace(); + if (StringUtil.isEmpty(liveArea)) { + hyPartnerLineDO.setErrorInfo(hyPartnerLineDO.getErrorInfo().concat(Constants.SEMICOLON).concat(ExcelErrorConstants.LIVEAREA_LOSE)); + ExcelUtil.setStyleMap(styleCells, i, 3, new String[]{ExcelUtil.FONT_RED}); + } else { + //判断格式是否为错 + if (ObjectUtil.isNull(hyOpenAreaInfoDAO.selectByAreaPath(liveArea))) { + hyPartnerLineDO.setErrorInfo(hyPartnerLineDO.getErrorInfo().concat(Constants.SEMICOLON).concat(ExcelErrorConstants.LIVEAREA_FORMAT_ERROR)); + ExcelUtil.setStyleMap(styleCells, i, 3, new String[]{ExcelUtil.FONT_RED}); + }else { + hyPartnerLineDO.setLiveArea(liveArea.replace(Constants.FORWARD_SLASH, Constants.SPACE)); + } + } + //意向区域 + String wantShopArea = hyPartnerLineDO.getWantShopAreaReplace(); + if (StringUtil.isEmpty(wantShopArea)) { + hyPartnerLineDO.setErrorInfo(hyPartnerLineDO.getErrorInfo().concat(Constants.SEMICOLON).concat(ExcelErrorConstants.WANTSHOPAREA_LOSE)); + ExcelUtil.setStyleMap(styleCells, i, 4, new String[]{ExcelUtil.FONT_RED}); + } else { + //判断格式是否为错 + HyOpenAreaInfoDO hyOpenAreaInfoDO = hyOpenAreaInfoDAO.selectByAreaPath(wantShopArea); + if (ObjectUtil.isNull(hyOpenAreaInfoDO)) { + hyPartnerLineDO.setErrorInfo(hyPartnerLineDO.getErrorInfo().concat(Constants.SEMICOLON).concat(ExcelErrorConstants.WANTSHOPAREA_FORMAT_ERROR)); + ExcelUtil.setStyleMap(styleCells, i, 4, new String[]{ExcelUtil.FONT_RED}); + }else { + hyPartnerLineDO.setWantShopArea(hyOpenAreaInfoDO.getId()); + } + } + //是否接受调剂 + String acceptAdjustType = hyPartnerLineDO.getAcceptAdjustTypeReplace(); + if (StringUtil.isEmpty(acceptAdjustType)) { + Integer enumByName = AcceptAdjustTypeEnum.findEnumByName(acceptAdjustType); + if(ObjectUtil.isNull(enumByName)){ + hyPartnerLineDO.setErrorInfo(hyPartnerLineDO.getErrorInfo().concat(Constants.SEMICOLON).concat(ExcelErrorConstants.ACCEPTADJUSTTYPE_LOSE)); + ExcelUtil.setStyleMap(styleCells, i, 5, new String[]{ExcelUtil.FONT_RED}); + }else { + hyPartnerLineDO.setAcceptAdjustType(enumByName); + } + } + //分配招商经理 + String investmentManager = hyPartnerLineDO.getInvestmentManagerReplace(); + if (StringUtil.isNotEmpty(investmentManager)) { + //判断是否能够查询的到 + EnterpriseUserDO enterpriseUserDO = enterpriseUserDAO.selectByInvestmentManager(investmentManager); + if (ObjectUtil.isNull(enterpriseUserDO)) { + hyPartnerLineDO.setErrorInfo(hyPartnerLineDO.getErrorInfo().concat(Constants.SEMICOLON).concat(ExcelErrorConstants.INVESTMENTMANAGER_LOSE)); + ExcelUtil.setStyleMap(styleCells, i, 6, new String[]{ExcelUtil.FONT_RED}); + }else { + hyPartnerLineDO.setInvestmentManager(enterpriseUserDO.getUserId()); + } + } + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + util.exportExcel(outputStream, lineDOList, "", styleCells); + InputStream stream = new ByteArrayInputStream(outputStream.toByteArray()); + String fileStr = ossServer.uploadFileServer(stream, ""); + if (styleCells.size() != 0) { + return new ResponseResult(500, "", new ErrorExcelResponse(lineDOList.size(), styleCells.size(), fileStr)); + } + for (HyPartnerLineDO hyPartnerLineDO : lineDOList) { + AddLineRequest addLineRequest = new AddLineRequest(); + BeanUtil.copyProperties(addLineRequest,hyPartnerLineDO); + addLineRequest.setWantShopArea(hyPartnerLineDO.getWantShopArea().toString()); + add(addLineRequest); + } + return new ResponseResult(200, "", new ErrorExcelResponse(lineDOList.size(), styleCells.size(), fileStr)); + } + + + /** + * @param phone 字符串类型的手机号 + * 传入手机号,判断后返回 + * true为手机号,false相反 + */ + private boolean isPhone(String phone) { + String regex = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$"; + if (phone.length() != 11) { + return false; + } else { + Pattern p = Pattern.compile(regex); + Matcher m = p.matcher(phone); + return m.matches(); + } + } +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/DateUtils.java b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/DateUtils.java new file mode 100644 index 000000000..aa5f0116c --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/DateUtils.java @@ -0,0 +1,223 @@ +package com.cool.store.utils.poi; + +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.lang.management.ManagementFactory; +import java.text.ParseException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.TemporalAdjusters; +import java.util.Date; + +/** + * 时间工具类 + * + * @author fanlyun + */ +public class DateUtils extends org.apache.commons.lang3.time.DateUtils +{ + public static String YYYY = "yyyy"; + + public static String YYYY_MM = "yyyy-MM"; + + public static String YYYY_MM_DD = "yyyy-MM-dd"; + + public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; + + public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; + + private static String[] parsePatterns = { + "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", + "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", + "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; + + /** + * 获取当前Date型日期 + * + * @return Date() 当前日期 + */ + public static Date getNowDate() + { + return new Date(); + } + + /** + * 获取当前日期, 默认格式为yyyy-MM-dd + * + * @return String + */ + public static String getDate() + { + return dateTimeNow(YYYY_MM_DD); + } + + public static String getTime() + { + return dateTimeNow(YYYY_MM_DD_HH_MM_SS); + } + + public static String dateTimeNow() + { + return dateTimeNow(YYYYMMDDHHMMSS); + } + + public static String dateTimeNow(final String format) + { + return parseDateToStr(format, new Date()); + } + + public static String dateTime(final Date date) + { + return parseDateToStr(YYYY_MM_DD, date); + } + + /** + * 格式化日期 + * @param format 格式化规则 + * @param date 日期 + * @return 格式化完毕的日期 + */ + public static String parseDateToStr(final String format, final Date date) + { + return new SimpleDateFormat(format).format(date); + } + + /** + * 以规则解析时间字符串 + * @param format 格式化规则 + * @param ts 时间字符串 + * @return 解析后时间 + */ + public static Date dateTime(final String format, final String ts) + { + try + { + return new SimpleDateFormat(format).parse(ts); + } + catch (ParseException e) + { + throw new RuntimeException(e); + } + } + + /** + * 日期路径 即年/月/日 如2018/08/08 + */ + public static String datePath() + { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyy/MM/dd"); + } + + /** + * 日期路径 即年/月/日 如20180808 + */ + public static String dateTime() + { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyyMMdd"); + } + + /** + * 日期型字符串转化为日期 格式 + */ + public static Date parseDate(Object str) + { + if (str == null) + { + return null; + } + try + { + return parseDate(str.toString(), parsePatterns); + } + catch (ParseException e) + { + return null; + } + } + + /** + * 获取服务器启动时间 + */ + public static Date getServerStartDate() + { + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + return new Date(time); + } + + /** + * 计算两个时间差 + */ + public static String getDatePoor(Date endDate, Date nowDate) + { + long nd = 1000 * 24 * 60 * 60; + long nh = 1000 * 60 * 60; + long nm = 1000 * 60; + // long ns = 1000; + // 获得两个时间的毫秒时间差异 + long diff = endDate.getTime() - nowDate.getTime(); + // 计算差多少天 + long day = diff / nd; + // 计算差多少小时 + long hour = diff % nd / nh; + // 计算差多少分钟 + long min = diff % nd % nh / nm; + // 计算差多少秒//输出结果 + // long sec = diff % nd % nh % nm / ns; + return day + "天" + hour + "小时" + min + "分钟"; + } + + /** + * 以规则解析时间字符串 + * @param strDate 时间字符串 + * @param pattern 格式化规则 + * @return 解析后时间 + */ + public static Date strToDate(String strDate, String pattern) { + SimpleDateFormat formatter = new SimpleDateFormat(pattern); + ParsePosition pos = new ParsePosition(0); + return formatter.parse(strDate, pos); + } + + /** + * 根据毫秒数获取时间 + * @param millis 毫秒数 + * @return 时间 + */ + public static String getDateByMillis(long millis) { + //12小时制 + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS); + Date date = new Date(); + date.setTime(millis); + return simpleDateFormat.format(date); + } + + + + public static String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm"; + + /** + * 返回11个月之前的月,从月的第一天开始,如当前是2020-05-03 返回的是2019-06-01 00:00:00 + * @return Date + */ + public static Date getNestOneYear() { + LocalDate minusDays = LocalDate.now().minusMonths(11).with(TemporalAdjusters.firstDayOfMonth()); + return fromDate(minusDays); + } + + /** + * 从1.8新增的{@link LocalDate}转换为{@link Date} + * @param localDate {@link LocalDate} + * @return 时间 + */ + private static Date fromDate(LocalDate localDate) { + ZoneId zone = ZoneId.systemDefault(); + Instant instant = localDate.atStartOfDay().atZone(zone).toInstant(); + return Date.from(instant); + } + +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/ExcelUtil.java b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/ExcelUtil.java new file mode 100644 index 000000000..8f67c2435 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/ExcelUtil.java @@ -0,0 +1,1153 @@ +package com.cool.store.utils.poi; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.EasyExcel; +import com.cool.store.annotation.Excel; +import com.cool.store.annotation.Excels; +import com.cool.store.utils.poi.constant.Constants; +import com.cool.store.utils.poi.reflect.ReflectUtils; +import com.cool.store.utils.poi.text.Convert; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +/** + * Excel相关处理 + * + * @author ruoyi + */ +public class ExcelUtil { + + private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); + /** + * 字体变红 + */ + public static String FONT_RED = "fontRed"; + + /** + * 背景色变绿 + */ + public static String BACKGROUND_COLOR_YELLOW = "backgroundColorYellow"; + + /** + * Excel sheet最大行数,默认65536 + */ + public static final int SHEET_SIZE = 65536; + + /** + * 工作表名称 + */ + private String sheetName; + + /** + * 导出类型(EXPORT:导出数据;IMPORT:导入模板) + */ + private Excel.Type type; + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 样式列表 + */ + private Map styles; + + /** + * 设置样式列表 map<行,map<列,样式>> + */ + private Map>> styleCells; + + /** + * 导入导出数据列表 + */ + private List list; + + /** + * 注解列表 + */ + private List fields; + + /** + * 统计列表 + */ + private Map statistics = new HashMap<>(); + + /** + * 数字格式 + */ + private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); + + /** + * 实体对象 + */ + public Class clazz; + + public ExcelUtil(Class clazz) { + this.clazz = clazz; + } + + + public void init(List list, String sheetName, Excel.Type type) { + if (list == null) { + list = new ArrayList<>(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + createExcelField(); + createWorkbook(); + } + + public void init(List list, String sheetName, Excel.Type type, Map>> styleCells) { + if (list == null) { + list = new ArrayList<>(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + this.styleCells = styleCells; + createExcelField(); + createWorkbook(); + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(InputStream is) throws Exception { + return importExcel(StringUtils.EMPTY, is); + } + + /** + * 对excel表单默认第一个索引名转换成list(EasyExcel) + * + * @param is 输入流 + * @return 转换后集合 + */ + public List importEasyExcel(InputStream is) throws Exception + { + return EasyExcel.read(is).head(clazz).sheet().doReadSync(); + } + + /** + * 对excel表单指定表格索引名转换成list + * + * @param sheetName 表格索引名 + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(String sheetName, InputStream is) throws Exception { + this.type = Excel.Type.IMPORT; + this.wb = WorkbookFactory.create(is); + List list = null; + Sheet sheet; + if (StringUtils.isNotEmpty(sheetName)) { + // 如果指定sheet名,则取指定sheet中的内容. + sheet = wb.getSheet(sheetName); + } else { + // 如果传入的sheet名不存在则默认指向第1个sheet. + sheet = wb.getSheetAt(0); + } + + if (sheet == null) { + throw new IOException("文件sheet不存在"); + } + + int rows = sheet.getPhysicalNumberOfRows(); + + if (rows > 0) { + // 定义一个map用于存放excel列的序号和field. + Map cellMap = new HashMap<>(16); + // 获取表头 + Row heard = sheet.getRow(0); + for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) { + Cell cell = heard.getCell(i); + if (ObjectUtil.isNotNull(cell)) { + String value = this.getCellValue(heard, i).toString(); + cellMap.put(value, i); + } else { + cellMap.put(null, i); + } + } + // 有数据时才处理 得到类的所有field. + Field[] allFields = clazz.getDeclaredFields(); + // 定义一个map用于存放列的序号和field. + Map fieldsMap = new HashMap<>(16); + for (Field field : allFields) { + Excel attr = field.getAnnotation(Excel.class); + // 判断字段是否为导出导入或为this.type + boolean isExportAndImport = attr != null && (attr.type() == Excel.Type.ALL || attr.type() == type); + if (isExportAndImport) { + // 设置类的私有字段属性可访问. + field.setAccessible(true); + Integer column = cellMap.get(attr.name()); + if (column != null) { + fieldsMap.put(column, field); + } + } + } + // 将数据填入集合 + list = fillCollection(sheet, rows, fieldsMap); + } + return list; + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + */ + public void exportExcel(HttpServletResponse response, List list, String sheetName) throws IOException { + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + this.init(list, sheetName, Excel.Type.EXPORT); + exportExcel(response.getOutputStream(),false); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + */ + public void exportExcel(HttpServletResponse response, List list, String sheetName, Map>> styleCells) throws IOException { + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + this.init(list, sheetName, Excel.Type.EXPORT, styleCells); + exportExcel(response.getOutputStream(),true); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + */ + public void exportExcel(OutputStream outputStream, List list, String sheetName, Map>> styleCells) throws IOException { + if (styleCells.size()==0) { + this.init(list, sheetName, Excel.Type.EXPORT); + }else { + this.init(list, sheetName, Excel.Type.EXPORT,styleCells); + } + exportExcel(outputStream,true); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + */ + public void importTemplateExcel(HttpServletResponse response, String sheetName) throws IOException { + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + this.init(null, sheetName, Excel.Type.IMPORT); + exportExcel(response.getOutputStream(),false); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * @param outputStream + * @param pan 是否设置样式 + */ + public void exportExcel(OutputStream outputStream,boolean pan) { + try { + // 取出一共有多少个sheet. + int sheetNo = list.size() % SHEET_SIZE > 0 ? list.size() / SHEET_SIZE + 1 : list.size() / SHEET_SIZE; + createSheet(sheetNo, 0); + for (int index = 0; index <= sheetNo; index++) { + // 产生一行 + Row row = sheet.createRow(0); + int column = 0; + // 写入各个字段的列头名称 + for (Object[] os : fields) { + Excel excel = (Excel) os[1]; + this.createCell(excel, row, column++); + } + if (Excel.Type.EXPORT.equals(type)) { + fillExcelData(index, row,pan); + addStatisticsRow(); + } + } + wb.write(outputStream); + } catch (Exception e) { + log.error("导出Excel异常{}", e.getMessage()); + } finally { + if (wb != null) { + try { + wb.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + } + + /** + * 填充excel数据 + * + * @param index 序号 + * @param row 单元格行 + */ + public void fillExcelData(int index, Row row,boolean pan) { + int startNo = index * SHEET_SIZE; + int endNo = Math.min(startNo + SHEET_SIZE, list.size()); + for (int i = startNo; i < endNo; i++) { + row = sheet.createRow(i + 1 - startNo); + // 得到导出对象. + T vo = (T) list.get(i); + int column = 0; + for (Object[] os : fields) { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + // 设置实体类私有属性可访问 + field.setAccessible(true); + this.addCell(excel, row, vo, field, column++, i,pan); + } + } + } + + /** + * 创建表格样式 + * + * @param wb 工作薄对象 + * @return 样式列表 + */ + private Map createStyles(Workbook wb) { + // 写入各条记录,每条记录对应excel表中的一行 + Map styles = new HashMap<>(16); + CellStyle style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBold(true); + headerFont.setColor(IndexedColors.WHITE.getIndex()); + style.setFont(headerFont); + styles.put("header", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font totalFont = wb.createFont(); + totalFont.setFontName("Arial"); + totalFont.setFontHeightInPoints((short) 10); + style.setFont(totalFont); + styles.put("total", style); + + return styles; + } + + + /** + * 创建单元格 + * + * @param attr 属性配置 + * @param row 行 + * @param column 列 + * @return 单元格 + */ + public Cell createCell(Excel attr, Row row, int column) { + // 创建列 + Cell cell = row.createCell(column); + // 写入列信息 + cell.setCellValue(attr.name()); + setDataValidation(attr, row, column); + //默认样式 + CellStyle cellStyle = styles.get("header"); + cell.setCellStyle(cellStyle); + return cell; + } + + /** + * 设置单元格信息 + * + * @param value 单元格值 + * @param attr 注解相关 + * @param cell 单元格信息 + */ + public void setCellVo(Object value, Excel attr, Cell cell) { + if (Excel.ColumnType.STRING == attr.cellType()) { + cell.setCellType(CellType.STRING); + cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); + } else if (Excel.ColumnType.NUMERIC == attr.cellType()) { + cell.setCellType(CellType.NUMERIC); + if (StringUtils.isNull(value)) { + cell.setCellValue(attr.defaultValue()); + } else { + cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); + } + } + } + + /** + * 创建表格样式 + */ + public void setDataValidation(Excel attr, Row row, int column) { + String prefix = "注:"; + if (attr.name().contains(prefix)) { + sheet.setColumnWidth(column, 6000); + } else { + // 设置列宽 + sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); + row.setHeight((short) (attr.height() * 20)); + } + // 如果设置了提示信息则鼠标放上去提示. + if (StringUtils.isNotEmpty(attr.prompt())) { + // 这里默认设了2-101列提示. + setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); + } + // 如果设置了combo属性则本列只能选择不能输入 + if (attr.combo().length > 0) { + // 这里默认设了2-101列只能选择不能输入. + setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); + } + } + + /** + * 添加单元格 + * + * @param attr 注解相关 + * @param row 单元行 + * @param vo 实体对象 + * @param field 字段 + * @param column 列 + * @return 单元格 + */ + public Cell addCell(Excel attr, Row row, T vo, Field field, int column, int lineNumber,boolean stylePan) { + Cell cell = null; + try { + // 设置行高 + row.setHeight((short) (attr.height() * 20)); + // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. + if (attr.isExport()) { + // 创建cell + cell = row.createCell(column); + // 用于读取对象中的属性 + Object value = getTargetValue(vo, field, attr); + String dateFormat = attr.dateFormat(); + String readConverterExp = attr.readConverterExp(); + String separator = attr.separator(); + //默认样式 + CellStyle cellStyle = cell.getRow().getSheet().getWorkbook().createCellStyle(); + cellStyle.cloneStyleFrom(styles.get("data")); + if(stylePan){ + if (styleCells.containsKey(lineNumber)) { + Map> columnMap = styleCells.get(lineNumber); + if (columnMap.containsKey(column)) { + List styleFlagList = columnMap.get(column); + boolean pan = true; + for (String styleFlag : styleFlagList) { + if (FONT_RED.equals(styleFlag)) { + //设置字体颜色 + setFontColor(cellStyle, IndexedColors.RED.index); + } + if (BACKGROUND_COLOR_YELLOW.equals(styleFlag)) { + //设置背景颜色 + cellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex()); + cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + //设置了背景颜色就不设置默认自定义背景颜色 + pan = false; + } + } + if (pan) { + setColumnsColor(attr, cellStyle); + } + } else { + //自定义样式 + setColumnsColor(attr, cellStyle); + } + cell.setCellStyle(cellStyle); + } else { + //自定义样式 + short columnsColor = attr.columnsColor(); + if (columnsColor != 0) { + //设置单元格的填充颜色 + cellStyle.setFillForegroundColor(columnsColor); + cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + cell.setCellStyle(cellStyle); + } else { + cell.setCellStyle(cellStyle); + } + } + } + if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) { + cell.setCellValue(parseDateToStr(dateFormat, (Date) value)); + } else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) { + cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); + } else if (value instanceof BigDecimal && -1 != attr.scale()) { + cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).stripTrailingZeros().toPlainString()); + } else { + // 设置列类型 + setCellVo(value, attr, cell); + } + addStatisticsData(column, Convert.toStr(value), attr); + } + } catch (Exception e) { + log.error("导出Excel失败{}", e); + } + return cell; + } + + + /** + * 格式化日期 + * @param format 格式化规则 + * @param date 日期 + * @return 格式化完毕的日期 + */ + public static String parseDateToStr(final String format, final Date date) + { + return new SimpleDateFormat(format).format(date); + } + + + /** + * 设置样式列 + * + * @param styleMap 样式map + * @param row 行号 + * @param sort 列号 + * @param styles 样式字符 + */ + public static void setStyleMap(Map>> styleMap, int row, int sort, String[] styles) { + if (styleMap.containsKey(row)) { + Map> columnListMap = styleMap.get(row); + if (columnListMap.containsKey(sort)) { + List list = columnListMap.get(sort); + list.addAll(Arrays.asList(styles)); + columnListMap.put(sort, list); + }else { + columnListMap.put(sort, Arrays.asList(styles)); + } + } else { + styleMap.put(row, new HashMap>() {{ + put(sort, Arrays.asList(styles)); + }}); + } + } + + + /** + * 设置整行样式 + * + * @param styleMap + * @param style + * @param columNumCount 总列数 + */ + public static void setRowStyle(Map>> styleMap, String style, int columNumCount) { + for (Integer row : styleMap.keySet()) { + boolean pan = false; + Map> integerListMap = styleMap.get(row); + for (int i = 0; i <= columNumCount; i++) { + if (pan) { + continue; + } + if (integerListMap.containsKey(i)) { + if (i == 0) { + pan = true; + } else { + List stringList = integerListMap.get(i); + stringList.add(style); + } + } else { + integerListMap.put(i, new ArrayList() {{ + add(style); + }}); + } + } + } + } + + + /** + * 自定义设置背景颜色 + * + * @param attr + * @param baseCellStyle + */ + private void setColumnsColor(Excel attr, CellStyle baseCellStyle) { + //自定义样式 + short columnsColor = attr.columnsColor(); + if (columnsColor != 0) { + //设置单元格的填充颜色 + baseCellStyle.setFillForegroundColor(columnsColor); + baseCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + } + } + + /** + * 自定义设置字体颜色 + * + * @param baseCellStyle + * @param color + */ + private void setFontColor(CellStyle baseCellStyle, short color) { + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + dataFont.setColor(color); + baseCellStyle.setFont(dataFont); + } + + /** + * 设置 POI XSSFSheet 单元格提示 + * + * @param sheet 表单 + * @param promptTitle 提示标题 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow, + int firstCol, int endCol) { + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + DataValidation dataValidation = helper.createValidation(constraint, regions); + dataValidation.createPromptBox(promptTitle, promptContent); + dataValidation.setShowPromptBox(true); + sheet.addValidationData(dataValidation); + } + + /** + * 设置某些列的值只能输入预制的数据,显示下拉框. + * + * @param sheet 要设置的sheet. + * @param textlist 下拉框显示的内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) { + DataValidationHelper helper = sheet.getDataValidationHelper(); + // 加载下拉列表内容 + DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, regions); + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + + sheet.addValidationData(dataValidation); + } + + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) { + String[] itemArray = item.split(Constants.EQUAL_SIGN); + if (StringUtils.containsAny(separator, propertyValue)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[0].equals(value)) { + propertyString.append(itemArray[1]).append(separator); + break; + } + } + } else { + if (itemArray[0].equals(propertyValue)) { + return itemArray[1]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) { + String[] itemArray = item.split(Constants.EQUAL_SIGN); + if (StringUtils.containsAny(separator, propertyValue)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[1].equals(value)) { + propertyString.append(itemArray[0]).append(separator); + break; + } + } + } else { + if (itemArray[1].equals(propertyValue)) { + return itemArray[0]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 合计统计信息 + */ + private void addStatisticsData(Integer index, String text, Excel entity) { + if (entity != null && entity.isStatistics()) { + Double temp = 0D; + if (!statistics.containsKey(index)) { + statistics.put(index, temp); + } + try { + temp = Double.valueOf(text); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + statistics.put(index, statistics.get(index) + temp); + } + } + + /** + * 创建统计行 + */ + public void addStatisticsRow() { + if (statistics.size() > 0) { + Cell cell = null; + Row row = sheet.createRow(sheet.getLastRowNum() + 1); + Set keys = statistics.keySet(); + cell = row.createCell(0); + cell.setCellStyle(styles.get("total")); + cell.setCellValue("合计"); + + for (Integer key : keys) { + cell = row.createCell(key); + cell.setCellStyle(styles.get("total")); + cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); + } + statistics.clear(); + } + } + + /** + * 获取bean中的属性值 + * + * @param vo 实体对象 + * @param field 字段 + * @param excel 注解 + * @return 最终的属性值 + * @throws Exception 没有找到字段 + */ + private Object getTargetValue(T vo, Field field, Excel excel) throws Exception { + Object o = field.get(vo); + if (StringUtils.isNotEmpty(excel.targetAttr())) { + String target = excel.targetAttr(); + if (target.contains(Constants.POMINT)) { + String[] targets = target.split("[.]"); + for (String name : targets) { + o = getValue(o, name); + } + } else { + o = getValue(o, target); + } + } + return o; + } + + /** + * 以类的属性的get方法方法形式获取值 + * + * @param o 实体对象 + * @param name 字段名 + * @return value + * @throws Exception 没有找到该字段 + */ + private Object getValue(Object o, String name) throws Exception { + if (StringUtils.isNotEmpty(name)) { + Class clazz = o.getClass(); + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + o = field.get(o); + } + return o; + } + + /** + * 得到所有定义字段 + */ + private void createExcelField() { + this.fields = new ArrayList<>(); + List tempFields = new ArrayList<>(); + tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); + tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); + for (Field field : tempFields) { + // 单注解 + if (field.isAnnotationPresent(Excel.class)) { + putToField(field, field.getAnnotation(Excel.class)); + } + + // 多注解 + if (field.isAnnotationPresent(Excels.class)) { + Excels attrs = field.getAnnotation(Excels.class); + Excel[] excels = attrs.value(); + for (Excel excel : excels) { + putToField(field, excel); + } + } + } + this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); + } + + /** + * 放到字段集合中 + */ + private void putToField(Field field, Excel attr) { + // 判断字段是否为导出导入或为this.type + boolean isExportAndImport = attr != null && (attr.type() == Excel.Type.ALL || attr.type() == type); + if (isExportAndImport) { + this.fields.add(new Object[]{field, attr}); + } + } + + /** + * 创建一个工作簿 + */ + public void createWorkbook() { + this.wb = new SXSSFWorkbook(500); + } + + /** + * 创建工作表 + * + * @param sheetNo sheet数量 + * @param index 序号 + */ + public void createSheet(double sheetNo, int index) { + this.sheet = wb.createSheet(); + this.styles = createStyles(wb); + // 设置工作表的名称. + if (sheetNo == 0) { + wb.setSheetName(index, sheetName); + } else { + wb.setSheetName(index, sheetName + index); + } + } + + /** + * 获取单元格值 + * + * @param row 获取的行 + * @param column 获取单元格列号 + * @return 单元格值 + */ + public Object getCellValue(Row row, int column) { + if (row == null) { + return row; + } + Object val = ""; + try { + Cell cell = row.getCell(column); + if (StringUtils.isNotNull(cell)) { + if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA) { + val = cell.getNumericCellValue(); + if (HSSFDateUtil.isCellDateFormatted(cell)) { + // POI Excel 日期格式转换 + val = DateUtil.getJavaDate((Double) val); + } else { + if ((Double) val % 1 > 0) { + val = new BigDecimal(val.toString()); + } else { + val = new DecimalFormat("0").format(val); + } + } + } else if (cell.getCellTypeEnum() == CellType.STRING) { + val = cell.getStringCellValue(); + } else if (cell.getCellTypeEnum() == CellType.BOOLEAN) { + val = cell.getBooleanCellValue(); + } else if (cell.getCellTypeEnum() == CellType.ERROR) { + val = cell.getErrorCellValue(); + } + + } + } catch (Exception e) { + return val; + } + return val; + } + + + private static ArrayList PoiDateList = new ArrayList() { + { + add("年"); + add("月"); + add("日"); + } + }; + + /** + * 获取单元格值 + * + * @param cell 单元格 + * @return String单元格值 + */ + public static String getCellValue(Cell cell) { + //判断是否为null或空串 + if (cell == null || "".equals(cell.toString().trim())) { + return ""; + } + CellType cellType = cell.getCellTypeEnum(); + String cellValue = ""; + // 1:字符串,2:数字,3:浮点,4:日期 + switch (cellType) { + //字符串类型 + case STRING: + cellValue = cell.getStringCellValue(); + //去除unicode字符串中的不可见字符 + cellValue = StringUtils.isEmpty(cellValue) ? "" : cellValue.trim() + .replaceAll("\\p{C}", ""); + break; + case BLANK: + cellValue = ""; + break; + // 数字 + case NUMERIC: + // 获取单元格值的格式化信息 + String dataFormat = cell.getCellStyle().getDataFormatString(); + // 判断格式化信息中是否存在:年月日 + AtomicReference isDate = new AtomicReference<>(false); + if (StringUtils.isNotNull(dataFormat)) { + PoiDateList.forEach(x -> isDate.set(isDate.get() || dataFormat.contains(x))); + } + + if (DateUtil.isCellDateFormatted(cell)) { + cellValue = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(DateUtil.getJavaDate(cell.getNumericCellValue())); + } else if (DateUtil.isCellInternalDateFormatted(cell)) { + cellValue = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(DateUtil.getJavaDate(cell.getNumericCellValue())); + } else if (isDate.get()) { + cellValue = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cell.getDateCellValue()); + } else if (dataFormat == null) { + cellValue = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(DateUtil.getJavaDate(cell.getNumericCellValue())); + } else { + if (StringUtils.isNull(dataFormat)) { + cellValue = String.valueOf(cell.getNumericCellValue()); + } else { + if (cell.getCellStyle().getDataFormatString().contains(Constants.USD)) { + cellValue = Constants.USD + cell.getNumericCellValue(); + } else if (cell.getCellStyle().getDataFormatString().contains(Constants.RMB_FULL)) { + cellValue = Constants.RMB_FULL + cell.getNumericCellValue(); + } else if (cell.getCellStyle().getDataFormatString().contains(Constants.RMB_HALF)) { + cellValue = Constants.RMB_HALF + cell.getNumericCellValue(); + } else if (cell.getCellStyle().getDataFormatString().contains(Constants.EUR)) { + cellValue = Constants.EUR + cell.getNumericCellValue(); + } else { + cellValue = String.valueOf(cell.getNumericCellValue()); + } + } + } + break; + default: + cellValue = ""; + break; + } + return cellValue; + } + + /** + * 获取单元格值 + * + * @param cell 单元格 + * @param cellType 单元格类型 + * @return String单元格值 + */ + public static String getCellValue(Cell cell, int cellType) { + //判断是否为null或空串 + if (cell == null || "".equals(cell.toString().trim())) { + return ""; + } + String cellValue = ""; + // 1:字符串,2:数字,3:浮点,4:日期 + switch (cellType) { + //字符串类型 + case 1: + cell.setCellType(CellType.STRING); + cellValue = cell.getStringCellValue(); + //去除unicode字符串中的不可见字符 + cellValue = StringUtils.isEmpty(cellValue) ? "" : cellValue.trim() + .replaceAll("\\p{C}", ""); + break; + // 数字 + case 2: + cellValue = new DecimalFormat("#").format(cell.getNumericCellValue()); + break; + //日期 + case 3: + cellValue = new DecimalFormat("#.###").format(cell.getNumericCellValue()); + break; + case 4: + // 获取单元格值的格式化信息 + String dataFormat = cell.getCellStyle().getDataFormatString(); + // 判断格式化信息中是否存在:年月日 + AtomicReference isDate = new AtomicReference<>(false); + if (StringUtils.isNotNull(dataFormat)) { + PoiDateList.forEach(x -> isDate.set(isDate.get() || dataFormat.contains(x))); + } + + if (DateUtil.isCellDateFormatted(cell)) { + cellValue = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(DateUtil.getJavaDate(cell.getNumericCellValue())); + } else if (DateUtil.isCellInternalDateFormatted(cell)) { + cellValue = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(DateUtil.getJavaDate(cell.getNumericCellValue())); + } else if (isDate.get()) { + cellValue = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cell.getDateCellValue()); + } else if (dataFormat == null) { + cellValue = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(DateUtil.getJavaDate(cell.getNumericCellValue())); + } else { + if (cell.getCellStyle().getDataFormatString().contains(Constants.USD)) { + cellValue = Constants.USD + cell.getNumericCellValue(); + } else if (cell.getCellStyle().getDataFormatString().contains(Constants.RMB_FULL)) { + cellValue = Constants.RMB_FULL + cell.getNumericCellValue(); + } else if (cell.getCellStyle().getDataFormatString().contains(Constants.RMB_HALF)) { + cellValue = Constants.RMB_HALF + cell.getNumericCellValue(); + } else if (cell.getCellStyle().getDataFormatString().contains(Constants.EUR)) { + cellValue = Constants.EUR + cell.getNumericCellValue(); + } else { + cellValue = String.valueOf(cell.getNumericCellValue()); + } + } + break; + default: + cellValue = ""; + break; + } + return cellValue; + } + + + /** + * 将数据填入集合 + * + * @param sheet sheet + * @param rows 行数 + * @param fieldsMap 用于存放列的序号和field + * @throws InstantiationException 实例创建异常 + * @throws IllegalAccessException 实例创建异常 + */ + private List fillCollection(Sheet sheet, int rows, Map fieldsMap) throws InstantiationException, IllegalAccessException { + List list = new ArrayList<>(); + for (int i = 1; i < rows; i++) { + // 从第2行开始取数据,默认第一行是表头. + Row row = sheet.getRow(i); + T entity = null; + for (Map.Entry entry : fieldsMap.entrySet()) { + Object val = this.getCellValue(row, entry.getKey()); + + // 如果不存在实例则新建. + entity = (entity == null ? clazz.newInstance() : entity); + // 从map中得到对应列的field. + Field field = fieldsMap.get(entry.getKey()); + // 取得类型,并根据对象类型设置值. + Class fieldType = field.getType(); + boolean isNumber = (Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)); + if (String.class == fieldType) { + String s = Convert.toStr(val); + if (StringUtils.endsWith(s, ".0")) { + val = StringUtils.substringBefore(s, ".0"); + } else { + val = Convert.toStr(val); + } + } else if (isNumber) { + val = Convert.toInt(val); + } else if (Long.TYPE == fieldType || Long.class == fieldType) { + val = Convert.toLong(val); + } else if (Double.TYPE == fieldType || Double.class == fieldType) { + val = Convert.toDouble(val); + } else if (Float.TYPE == fieldType || Float.class == fieldType) { + val = Convert.toFloat(val); + } else if (BigDecimal.class == fieldType) { + val = Convert.toBigDecimal(val); + } else if (Date.class == fieldType) { + if (val instanceof String) { + val = DateUtils.parseDate(val); + } else if (val instanceof Double) { + val = DateUtil.getJavaDate((Double) val); + } + } + Excel attr = field.getAnnotation(Excel.class); + String propertyName = field.getName(); + if (StringUtils.isNotEmpty(attr.targetAttr())) { + propertyName = field.getName() + "." + attr.targetAttr(); + } else if (StringUtils.isNotEmpty(attr.readConverterExp())) { + val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); + } + ReflectUtils.invokeSetter(entity, propertyName, val); + } + list.add(entity); + } + return list; + } + + + +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/StringUtils.java b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/StringUtils.java new file mode 100644 index 000000000..df135fb3d --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/StringUtils.java @@ -0,0 +1,522 @@ +package com.cool.store.utils.poi; + +import cn.hutool.core.text.StrFormatter; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 字符串工具类 + * + * @author ruoyi + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils +{ + /** 空字符串 */ + private static final String NULLSTR = ""; + + /** 下划线 */ + private static final char SEPARATOR = '_'; + + /** 星号 */ + private static final String START = "*"; + + /** + * 获取参数不为空值 + * + * @param value defaultValue 要判断的value + * @return value 返回值 + */ + public static T nvl(T value, T defaultValue) + { + return value != null ? value : defaultValue; + } + + /** + * * 判断一个Collection是否为空, 包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Collection coll) + { + return isNull(coll) || coll.isEmpty(); + } + + /** + * * 判断一个Collection是否非空,包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Collection coll) + { + return !isEmpty(coll); + } + + /** + * * 判断一个对象数组是否为空 + * + * @param objects 要判断的对象数组 + ** @return true:为空 false:非空 + */ + public static boolean isEmpty(Object[] objects) + { + return isNull(objects) || (objects.length == 0); + } + + /** + * * 判断一个对象数组是否非空 + * + * @param objects 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object[] objects) + { + return !isEmpty(objects); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Map map) + { + return isNull(map) || map.isEmpty(); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Map map) + { + return !isEmpty(map); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) + { + return isNull(str) || NULLSTR.equals(str.trim()); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) + { + return !isEmpty(str); + } + + /** + * * 判断一个对象是否为空 + * + * @param object Object + * @return true:为空 false:非空 + */ + public static boolean isNull(Object object) + { + return object == null; + } + + /** + * * 判断一个对象是否非空 + * + * @param object Object + * @return true:非空 false:空 + */ + public static boolean isNotNull(Object object) + { + return !isNull(object); + } + + /** + * * 判断一个对象是否是数组类型(Java基本型别的数组) + * + * @param object 对象 + * @return true:是数组 false:不是数组 + */ + public static boolean isArray(Object object) + { + return isNotNull(object) && object.getClass().isArray(); + } + + /** + * 去空格 + */ + public static String trim(String str) + { + return (str == null ? "" : str.trim()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) + { + if (str == null) + { + return NULLSTR; + } + + if (start < 0) + { + start = str.length() + start; + } + + if (start < 0) + { + start = 0; + } + if (start > str.length()) + { + return NULLSTR; + } + + return str.substring(start); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) + { + if (str == null) + { + return NULLSTR; + } + + if (end < 0) + { + end = str.length() + end; + } + if (start < 0) + { + start = str.length() + start; + } + + if (end > str.length()) + { + end = str.length(); + } + + if (start > end) + { + return NULLSTR; + } + + if (start < 0) + { + start = 0; + } + if (end < 0) + { + end = 0; + } + + return str.substring(start, end); + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) + { + if (isEmpty(params) || isEmpty(template)) + { + return template; + } + return StrFormatter.format(template, params); + } + + /** + * 下划线转驼峰命名 + */ + public static String toUnderScoreCase(String str) + { + if (str == null) + { + return null; + } + StringBuilder sb = new StringBuilder(); + // 前置字符是否大写 + boolean preCharIsUpperCase = true; + // 当前字符是否大写 + boolean curreCharIsUpperCase = true; + // 下一字符是否大写 + boolean nexteCharIsUpperCase = true; + for (int i = 0; i < str.length(); i++) + { + char c = str.charAt(i); + if (i > 0) + { + preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + } + else + { + preCharIsUpperCase = false; + } + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) + { + nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + } + + // 分词 + boolean participles = (i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase; + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) + { + sb.append(SEPARATOR); + } + else if (participles) + { + sb.append(SEPARATOR); + } + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) + { + if (str != null && strs != null) + { + for (String s : strs) + { + if (str.equalsIgnoreCase(trim(s))) + { + return true; + } + } + } + return false; + } + + /** + * 驼峰式命名法 例如:user_name->userName + */ + public static String toCamelCase(String s) + { + if (s == null) + { + return null; + } + s = s.toLowerCase(); + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) + { + char c = s.charAt(i); + + if (c == SEPARATOR) + { + upperCase = true; + } + else if (upperCase) + { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } + else + { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) + { + if (isEmpty(str) || isEmpty(strs)) + { + return false; + } + for (String testStr : strs) + { + if (matches(str, testStr)) + { + return true; + } + } + return false; + } + + /** + * 查找指定字符串是否匹配指定字符串数组中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, String... strs) + { + if (isEmpty(str) || isEmpty(strs)) + { + return false; + } + for (String testStr : strs) + { + if (matches(str, testStr)) + { + return true; + } + } + return false; + } + + /** + * 查找指定字符串是否匹配 + * + * @param str 指定字符串 + * @param pattern 需要检查的字符串 + * @return 是否匹配 + */ + public static boolean matches(String str, String pattern) + { + if (isEmpty(pattern) || isEmpty(str)) + { + return false; + } + + // 替换空格 + pattern = pattern.replaceAll("\\s*", ""); + // pattern截取开始位置 + int beginOffset = 0; + // 前星号的偏移位置 + int formerStarOffset; + // 后星号的偏移位置 + int latterStarOffset; + + String remainingUri = str; + String prefixPattern; + String suffixPattern; + + boolean result; + do + { + formerStarOffset = indexOf(pattern, START, beginOffset); + prefixPattern = substring(pattern, beginOffset, formerStarOffset > -1 ? formerStarOffset : pattern.length()); + + // 匹配前缀Pattern + result = remainingUri.contains(prefixPattern); + // 已经没有星号,直接返回 + if (formerStarOffset == -1) + { + return result; + } + + // 匹配失败,直接返回 + if (!result) { + return false; + } + + if (!isEmpty(prefixPattern)) + { + remainingUri = substringAfter(str, prefixPattern); + } + + // 匹配后缀Pattern + latterStarOffset = indexOf(pattern, START, formerStarOffset + 1); + suffixPattern = substring(pattern, formerStarOffset + 1, latterStarOffset > -1 ? latterStarOffset : pattern.length()); + + result = remainingUri.contains(suffixPattern); + // 匹配失败,直接返回 + if (!result) { + return false; + } + + if (!isEmpty(suffixPattern)) + { + remainingUri = substringAfter(str, suffixPattern); + } + + // 移动指针 + beginOffset = latterStarOffset + 1; + + } + while (!isEmpty(suffixPattern) && !isEmpty(remainingUri)); + + return true; + } + + @SuppressWarnings("unchecked") + public static T cast(Object obj) + { + return (T) obj; + } + + /** + * 判断是否非空 + * @param values 待校验的字符串 + * @return 是否所有非空 + */ + public static boolean areNotEmpty(String... values) { + boolean result = true; + if ((values == null) || (values.length == 0)) { + result = false; + } else { + for (String value : values) { + result &= !isEmpty(value); + } + } + return result; + } + + /** 首字母转小写 */ + public static String toLowerCaseFirstOne(String s) { + if(Character.isLowerCase(s.charAt(0))) { + return s; + } else { + return Character.toLowerCase(s.charAt(0)) + s.substring(1); + } + } +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/constant/Constants.java b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/constant/Constants.java new file mode 100644 index 000000000..c4e8ee514 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/constant/Constants.java @@ -0,0 +1,166 @@ +package com.cool.store.utils.poi.constant; + +/** + * 通用常量信息 + * + * @author ruoyi + */ +public class Constants +{ + /** + * UTF-8 字符集 + */ + public static final String UTF8 = "UTF-8"; + + /** + * GBK 字符集 + */ + public static final String GBK = "GBK"; + + /** + * http请求 + */ + public static final String HTTP = "http://"; + + /** + * info 信息 + */ + public static final String INFO = "INFO:"; + + /** + * https请求 + */ + public static final String HTTPS = "https://"; + + /** + * 成功标记 + */ + public static final Integer SUCCESS = 200; + + /** + * 失败标记 + */ + public static final Integer FAIL = 500; + + + /** + * 登录失败 + */ + public static final String LOGIN_FAIL = "Error"; + + /** + * 等号 + */ + public static final String EQUAL_SIGN = "="; + /** + * 逗号 + */ + public static final String COMMA = ","; + + /** + * 单引号 + */ + public static final String SINGLE_QUOTES = "'"; + /** + * 小数点 + */ + public static final String POMINT = "."; + /** + * 冒号 + */ + public static final String COLON = ":"; + /** + * 分号 + */ + public static final String SEMICOLON = ";"; + + /** + * 空格 + */ + public static final String SPACE = " "; + /** + * 横线 + */ + public static final String M_LINE = "-"; + /** + * 下划线 + */ + public static final String D_LINE = "_"; + + + public static final String SEPARATOR= "\\|"; + + + public static final String FORWARD_SLASH = "/"; + + /** + * 图片格式 + */ + public static final String IMAGE_PNG = "png"; + + /** + * 图片格式 + */ + public static final String IMAGE_JPG = "jpg"; + /** + * 图片格式 + */ + public static final String IMAGE_POINT_PNG = ".png"; + + /** + * 图片格式 + */ + public static final String IMAGE_POINT_JPG = ".jpg"; + + /** + * 删除标识-0 + */ + public static final String DEL_FLAG_0 = "0"; + /** + * 删除标识-1 + */ + public static final String STR_WITH = "&"; + + /** + * 删除标识-1 + */ + public static final String DEL_FLAG_1 = "1"; + + + /** + * 字符串-未知 + */ + public static final String UNKNOWN = "unknown"; + + /** + * 美元 + */ + public static final String USD = "$"; + + /** + * 人民币 全角 + */ + public static final String RMB_FULL = "¥"; + + /** + * 人民币 半角 + */ + public static final String RMB_HALF = "¥"; + + /** + * 欧元 + */ + public static final String EUR = "€"; + + /** + * 小写MD5 + */ + public static final String MD5 = "md5"; + + /** + * 请求头 Content-Encoding + */ + public static final String CONTENT_ENCODING = "Content-Encoding"; + + +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/reflect/ReflectUtils.java b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/reflect/ReflectUtils.java new file mode 100644 index 000000000..3119fe538 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/reflect/ReflectUtils.java @@ -0,0 +1,403 @@ +package com.cool.store.utils.poi.reflect; + +import com.cool.store.utils.poi.DateUtils; +import com.cool.store.utils.poi.constant.Constants; +import com.cool.store.utils.poi.text.Convert; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.apache.poi.ss.usermodel.DateUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.*; +import java.util.Arrays; +import java.util.Date; + +/** + * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + * + * @author ruoyi + */ +@SuppressWarnings("rawtypes") +public class ReflectUtils +{ + private static final String SETTER_PREFIX = "set"; + + private static final String GETTER_PREFIX = "get"; + + private static final String CGLIB_CLASS_SEPARATOR = "$$"; + + private static final Logger logger = LoggerFactory.getLogger(ReflectUtils.class); + + /** + * 调用Getter方法. + * 支持多级,如:对象名.对象名.方法 + */ + @SuppressWarnings("unchecked") + public static E invokeGetter(Object obj, String propertyName) + { + Object object = obj; + for (String name : StringUtils.split(propertyName, Constants.POMINT)) + { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); + object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + } + return (E) object; + } + + /** + * 调用Setter方法, 仅匹配方法名。 + * 支持多级,如:对象名.对象名.方法 + */ + public static 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 = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + } + else + { + String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); + invokeMethodByName(object, setterMethodName, new Object[] { value }); + } + } + } + + /** + * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. + */ + @SuppressWarnings("unchecked") + public static E getFieldValue(final Object obj, final String fieldName) + { + Field field = getAccessibleField(obj, fieldName); + if (field == null) + { + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return null; + } + E result = null; + try + { + result = (E) field.get(obj); + } + catch (IllegalAccessException e) + { + logger.error("不可能抛出的异常{}", e.getMessage()); + } + return result; + } + + /** + * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. + */ + public static void setFieldValue(final Object obj, final String fieldName, final E value) + { + Field field = getAccessibleField(obj, fieldName); + if (field == null) + { + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return; + } + try + { + field.set(obj, value); + } + catch (IllegalAccessException e) + { + logger.error("不可能抛出的异常: {}", e.getMessage()); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符. + * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用. + * 同时匹配方法名+参数类型, + */ + @SuppressWarnings("unchecked") + public static E invokeMethod(final Object obj, final String methodName, final Class[] parameterTypes, + final Object[] args) + { + if (obj == null || methodName == null) + { + return null; + } + Method method = getAccessibleMethod(obj, methodName, parameterTypes); + if (method == null) + { + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); + return null; + } + try + { + return (E) method.invoke(obj, args); + } + catch (Exception e) + { + String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; + throw convertReflectionExceptionToUnchecked(msg, e); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符, + * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. + * 只匹配函数名,如果有多个同名函数调用第一个。 + */ + @SuppressWarnings("unchecked") + public static E invokeMethodByName(final Object obj, final String methodName, final Object[] args) + { + Method method = getAccessibleMethodByName(obj, methodName, args.length); + if (method == null) + { + // 如果为空不报错,直接返回空。 + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); + return null; + } + try + { + // 类型转换(将参数数据类型转换为目标方法参数类型) + Class[] cs = method.getParameterTypes(); + for (int i = 0; i < cs.length; i++) + { + if (args[i] != null && !args[i].getClass().equals(cs[i])) + { + if (cs[i] == String.class) + { + args[i] = Convert.toStr(args[i]); + if (StringUtils.endsWith((String) args[i], ".0")) + { + args[i] = StringUtils.substringBefore((String) args[i], ".0"); + } + } + else if (cs[i] == Integer.class) + { + args[i] = Convert.toInt(args[i]); + } + else if (cs[i] == Long.class) + { + args[i] = Convert.toLong(args[i]); + } + else if (cs[i] == Double.class) + { + args[i] = Convert.toDouble(args[i]); + } + else if (cs[i] == Float.class) + { + args[i] = Convert.toFloat(args[i]); + } + else if (cs[i] == Date.class) + { + if (args[i] instanceof String) + { + args[i] = DateUtils.parseDate(args[i]); + } + else + { + args[i] = DateUtil.getJavaDate((Double) args[i]); + } + } + } + } + return (E) method.invoke(obj, args); + } + catch (Exception e) + { + String msg = "method: " + method + ", obj: " + obj + ", args: " + Arrays.toString(args) + ""; + throw convertReflectionExceptionToUnchecked(msg, e); + } + } + + /** + * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + */ + public static Field getAccessibleField(final Object obj, final String fieldName) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(fieldName, "fieldName can't be blank"); + for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) + { + try + { + Field field = superClass.getDeclaredField(fieldName); + makeAccessible(field); + return field; + } + catch (NoSuchFieldException e) + { + e.printStackTrace(); + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 匹配函数名+参数类型。 + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethod(final Object obj, final String methodName, + final Class... parameterTypes) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(methodName, "methodName can't be blank"); + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) + { + try + { + Method method = searchType.getDeclaredMethod(methodName, parameterTypes); + makeAccessible(method); + return method; + } + catch (NoSuchMethodException e) + { + e.printStackTrace(); + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 只匹配函数名。 + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(methodName, "methodName can't be blank"); + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) + { + Method[] methods = searchType.getDeclaredMethods(); + for (Method method : methods) + { + if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) + { + makeAccessible(method); + return method; + } + } + } + return null; + } + + /** + * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + */ + public static void makeAccessible(Method method) + { + boolean notAccessible = (!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) + && !method.isAccessible(); + if (notAccessible) { + method.setAccessible(true); + } + } + + /** + * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + */ + public static void makeAccessible(Field field) + { + boolean notAccessible = (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) + || Modifier.isFinal(field.getModifiers())) && !field.isAccessible(); + if (notAccessible) { + field.setAccessible(true); + } + } + + /** + * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处 + * 如无法找到, 返回Object.class. + */ + @SuppressWarnings("unchecked") + public static Class getClassGenricType(final Class clazz) + { + return getClassGenricType(clazz, 0); + } + + /** + * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. + * 如无法找到, 返回Object.class. + */ + public static Class getClassGenricType(final Class clazz, final int index) + { + Type genType = clazz.getGenericSuperclass(); + + if (!(genType instanceof ParameterizedType)) + { + logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType"); + return Object.class; + } + + Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); + + if (index >= params.length || index < 0) + { + logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + + params.length); + return Object.class; + } + if (!(params[index] instanceof Class)) + { + logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); + return Object.class; + } + + return (Class) params[index]; + } + + public static Class getUserClass(Object instance) + { + if (instance == null) + { + throw new RuntimeException("Instance must not be null"); + } + Class clazz = instance.getClass(); + if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) + { + Class superClass = clazz.getSuperclass(); + if (superClass != null && !Object.class.equals(superClass)) + { + return superClass; + } + } + return clazz; + + } + + /** + * 将反射时的checked exception转换为unchecked exception. + */ + public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) + { + if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException + || e instanceof NoSuchMethodException) + { + return new IllegalArgumentException(msg, e); + } + else if (e instanceof InvocationTargetException) + { + return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException()); + } + return new RuntimeException(msg, e); + } +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/text/Convert.java b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/text/Convert.java new file mode 100644 index 000000000..d4526c088 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/text/Convert.java @@ -0,0 +1,998 @@ +package com.cool.store.utils.poi.text; + + +import com.cool.store.utils.poi.StringUtils; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.text.NumberFormat; +import java.util.Set; + +/** + * 类型转换器 + * + * @author fanlyun + */ +public class Convert +{ + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static String toStr(Object value, String defaultValue) + { + if (null == value) + { + return defaultValue; + } + if (value instanceof String) + { + return (String) value; + } + return value.toString(); + } + + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static String toStr(Object value) + { + return toStr(value, null); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Character toChar(Object value, Character defaultValue) + { + if (null == value) + { + return defaultValue; + } + if (value instanceof Character) + { + return (Character) value; + } + + final String valueStr = toStr(value, null); + return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Character toChar(Object value) + { + return toChar(value, null); + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Byte toByte(Object value, Byte defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Byte) + { + return (Byte) value; + } + if (value instanceof Number) + { + return ((Number) value).byteValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Byte.parseByte(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Byte toByte(Object value) + { + return toByte(value, null); + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Short toShort(Object value, Short defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Short) + { + return (Short) value; + } + if (value instanceof Number) + { + return ((Number) value).shortValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Short.parseShort(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Short toShort(Object value) + { + return toShort(value, null); + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Number toNumber(Object value, Number defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Number) + { + return (Number) value; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return NumberFormat.getInstance().parse(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Number toNumber(Object value) + { + return toNumber(value, null); + } + + /** + * 转换为int
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Integer toInt(Object value, Integer defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Integer) + { + return (Integer) value; + } + if (value instanceof Number) + { + return ((Number) value).intValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Integer.parseInt(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为int
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Integer toInt(Object value) + { + return toInt(value, null); + } + + /** + * 转换为Integer数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String str) + { + return toIntArray(",", str); + } + + /** + * 转换为Long数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String str) + { + return toLongArray(",", str); + } + + /** + * 转换为Integer数组
+ * + * @param split 分隔符 + * @param str 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String split, String str) + { + if (StringUtils.isEmpty(str)) + { + return new Integer[] {}; + } + String[] arr = str.split(split); + final Integer[] ints = new Integer[arr.length]; + for (int i = 0; i < arr.length; i++) + { + final Integer v = toInt(arr[i], 0); + ints[i] = v; + } + return ints; + } + + /** + * 转换为Long数组
+ * + * @param split 分隔符 + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String split, String str) + { + if (StringUtils.isEmpty(str)) + { + return new Long[] {}; + } + String[] arr = str.split(split); + final Long[] longs = new Long[arr.length]; + for (int i = 0; i < arr.length; i++) + { + final Long v = toLong(arr[i], null); + longs[i] = v; + } + return longs; + } + + /** + * 转换为String数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String str) + { + return toStrArray(",", str); + } + + /** + * 转换为String数组
+ * + * @param split 分隔符 + * @param str 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String split, String str) + { + return str.split(split); + } + + /** + * 转换为long
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Long toLong(Object value, Long defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Long) + { + return (Long) value; + } + if (value instanceof Number) + { + return ((Number) value).longValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).longValue(); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为long
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Long toLong(Object value) + { + return toLong(value, null); + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Double toDouble(Object value, Double defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Double) + { + return (Double) value; + } + if (value instanceof Number) + { + return ((Number) value).doubleValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).doubleValue(); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Double toDouble(Object value) + { + return toDouble(value, null); + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Float toFloat(Object value, Float defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Float) + { + return (Float) value; + } + if (value instanceof Number) + { + return ((Number) value).floatValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Float.parseFloat(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Float toFloat(Object value) + { + return toFloat(value, null); + } + + /** + * 转换为boolean
+ * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Boolean toBool(Object value, Boolean defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Boolean) + { + return (Boolean) value; + } + String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + valueStr = valueStr.trim().toLowerCase(); + switch (valueStr) + { + // 为 true、yes、ok、1 时均认为 true + case "true": + case "yes": + case "ok": + case "1": + return true; + //否则认为 false + case "false": + case "no": + case "0": + return false; + default: + return defaultValue; + } + } + + /** + * 转换为boolean
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Boolean toBool(Object value) + { + return toBool(value, null); + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * + * @param clazz Enum的Class + * @param value 值 + * @param defaultValue 默认值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value, E defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (clazz.isAssignableFrom(value.getClass())) + { + @SuppressWarnings("unchecked") + E myE = (E) value; + return myE; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Enum.valueOf(clazz, valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * + * @param clazz Enum的Class + * @param value 值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value) + { + return toEnum(clazz, value, null); + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value, BigInteger defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof BigInteger) + { + return (BigInteger) value; + } + if (value instanceof Long) + { + return BigInteger.valueOf((Long) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return new BigInteger(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value) + { + return toBigInteger(value, null); + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof BigDecimal) + { + return (BigDecimal) value; + } + if (value instanceof Long) + { + return new BigDecimal((Long) value); + } + if (value instanceof Double) + { + return BigDecimal.valueOf((Double) value); + } + if (value instanceof Integer) + { + return new BigDecimal((Integer) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return new BigDecimal(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value) + { + return toBigDecimal(value, null); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @return 字符串 + */ + public static String utf8Str(Object obj) + { + return str(obj, StandardCharsets.UTF_8); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charsetName 字符集 + * @return 字符串 + */ + public static String str(Object obj, String charsetName) + { + return str(obj, Charset.forName(charsetName)); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(Object obj, Charset charset) + { + if (null == obj) + { + return null; + } + + if (obj instanceof String) + { + return (String) obj; + } + else if (obj instanceof byte[] || obj instanceof Byte[]) + { + return str(obj, charset); + } + else if (obj instanceof ByteBuffer) + { + return str((ByteBuffer) obj, charset); + } + return obj.toString(); + } + + /** + * 将byte数组转为字符串 + * + * @param bytes byte数组 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(byte[] bytes, String charset) + { + return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset)); + } + + /** + * 解码字节码 + * + * @param data 字符串 + * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 + * @return 解码后的字符串 + */ + public static String str(byte[] data, Charset charset) + { + if (data == null) + { + return null; + } + + if (null == charset) + { + return new String(data); + } + return new String(data, charset); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, String charset) + { + if (data == null) + { + return null; + } + + return str(data, Charset.forName(charset)); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, Charset charset) + { + if (null == charset) + { + charset = Charset.defaultCharset(); + } + return charset.decode(data).toString(); + } + + // ----------------------------------------------------------------------- 全角半角转换 + /** + * 半角转全角 + * + * @param input String. + * @return 全角字符串. + */ + public static String toSBC(String input) + { + return toSBC(input, null); + } + + /** + * 半角转全角 + * + * @param input String + * @param notConvertSet 不替换的字符集合 + * @return 全角字符串. + */ + public static String toSBC(String input, Set notConvertSet) + { + char[] c = input.toCharArray(); + for (int i = 0; i < c.length; i++) + { + if (null != notConvertSet && notConvertSet.contains(c[i])) + { + // 跳过不替换的字符 + continue; + } + + if (c[i] == ' ') + { + c[i] = '\u3000'; + } + else if (c[i] < '\177') + { + c[i] = (char) (c[i] + 65248); + + } + } + return new String(c); + } + + /** + * 全角转半角 + * + * @param input String. + * @return 半角字符串 + */ + public static String toDBC(String input) + { + return toDBC(input, null); + } + + /** + * 替换全角为半角 + * + * @param text 文本 + * @param notConvertSet 不替换的字符集合 + * @return 替换后的字符 + */ + public static String toDBC(String text, Set notConvertSet) + { + char[] c = text.toCharArray(); + for (int i = 0; i < c.length; i++) + { + if (null != notConvertSet && notConvertSet.contains(c[i])) + { + // 跳过不替换的字符 + continue; + } + + if (c[i] == '\u3000') + { + c[i] = ' '; + } + else if (c[i] > '\uFF00' && c[i] < '\uFF5F') + { + c[i] = (char) (c[i] - 65248); + } + } + + return new String(c); + } + + /** + * 数字金额大写转换 先写个完整的然后将如零拾替换成零 + * + * @param n 数字 + * @return 中文大写数字 + */ + public static String digitUppercase(double n) + { + String[] fraction = { "角", "分" }; + String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; + String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } }; + + String head = n < 0 ? "负" : ""; + n = Math.abs(n); + + StringBuilder s = new StringBuilder(); + for (int i = 0; i < fraction.length; i++) + { + s.append((digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "")); + } + if (s.length() < 1) + { + s = new StringBuilder("整"); + } + int integerPart = (int) Math.floor(n); + + for (int i = 0; i < unit[0].length && integerPart > 0; i++) + { + StringBuilder p = new StringBuilder(); + for (int j = 0; j < unit[1].length && n > 0; j++) + { + p.insert(0, digit[integerPart % 10] + unit[1][j]); + integerPart = integerPart / 10; + } + s.insert(0, p.toString().replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i]); + } + return head + s.toString().replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整"); + } +} diff --git a/coolstore-partner-webb/src/main/java/com/cool/store/controller/LineHighSeasController.java b/coolstore-partner-webb/src/main/java/com/cool/store/controller/LineHighSeasController.java new file mode 100644 index 000000000..8c4f5cf08 --- /dev/null +++ b/coolstore-partner-webb/src/main/java/com/cool/store/controller/LineHighSeasController.java @@ -0,0 +1,48 @@ +package com.cool.store.controller; + + +import com.cool.store.entity.HyPartnerLineDO; +import com.cool.store.exception.ApiException; +import com.cool.store.request.AddLineRequest; +import com.cool.store.response.ResponseResult; +import com.cool.store.service.LineHighSeasService; +import com.cool.store.utils.poi.ExcelUtil; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +/** + * @Author: hxd + * @Date: 2023-06-06 15:22 + * @Description: + */ +@RestController +@RequestMapping("/line/highSeas") +public class LineHighSeasController { + + + @Resource + private LineHighSeasService lineHighSeasService; + + @PostMapping("/add") + @ApiOperation("新建线索") + public ResponseResult addLine(@RequestBody @Valid AddLineRequest request) throws ApiException { + + return ResponseResult.success(lineHighSeasService.addLine(request)); + } + + + + @PostMapping("/import") + @ApiOperation("批量导入线索") + public ResponseResult importLine(MultipartFile file) throws Exception { + return lineHighSeasService.importLine(file); + } +} diff --git a/pom.xml b/pom.xml index e4b63e2a5..ad5e7b41f 100644 --- a/pom.xml +++ b/pom.xml @@ -213,6 +213,17 @@ pom import + + + com.alibaba + easyexcel + 2.2.6 + + + org.apache.poi + poi-ooxml + 3.17 +