From 2b6d8137dbccaff7eeb062ae56cf51ab49c15820 Mon Sep 17 00:00:00 2001 From: CCass Date: Wed, 24 Sep 2025 23:04:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=99=E8=82=B2=E9=83=A8=E5=9B=BA=E5=AE=9A?= =?UTF-8?q?=E8=B5=84=E4=BA=A7=E6=9C=80=E4=BD=8E=E4=BD=BF=E7=94=A8=E5=B9=B4?= =?UTF-8?q?=E9=99=90=E8=A7=84=E5=AE=9A=EF=BC=8C=E6=95=B0=E6=8D=AE=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E4=BB=A5=E5=8F=8A=E5=85=A5=E5=BA=93=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: CCass --- .../ruoyi/system/domain/MinUsagePeriod.java | 51 ++++ .../system/domain/bo/MinUsagePeriodBo.java | 56 ++++ .../domain/vo/MinUsagePeriodImportVo.java | 47 ++++ .../system/domain/vo/MinUsagePeriodVo.java | 63 +++++ .../system/mapper/MinUsagePeriodMapper.java | 17 ++ .../service/IMinUsagePeriodService.java | 60 ++++ ruoyi-modules/ruoyi-system/pom.xml | 13 + .../MinUsagePeriodImportListener.java | 107 +++++++ .../impl/MinUsagePeriodServiceImpl.java | 183 ++++++++++++ .../system/service/DatabaseImportTest.java | 261 ++++++++++++++++++ .../system/service/DatabaseInitTest.java | 114 ++++++++ .../system/service/ExcelImportSimpleTest.java | 172 ++++++++++++ .../system/service/SimpleDatabaseTest.java | 233 ++++++++++++++++ .../system/service/SimpleExcelImportTest.java | 169 ++++++++++++ script/sql/min_usage_period.sql | 17 ++ 15 files changed, 1563 insertions(+) create mode 100644 ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/MinUsagePeriod.java create mode 100644 ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/MinUsagePeriodBo.java create mode 100644 ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/MinUsagePeriodImportVo.java create mode 100644 ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/MinUsagePeriodVo.java create mode 100644 ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/MinUsagePeriodMapper.java create mode 100644 ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/IMinUsagePeriodService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/listener/MinUsagePeriodImportListener.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/MinUsagePeriodServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/DatabaseImportTest.java create mode 100644 ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/DatabaseInitTest.java create mode 100644 ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/ExcelImportSimpleTest.java create mode 100644 ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/SimpleDatabaseTest.java create mode 100644 ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/SimpleExcelImportTest.java create mode 100644 script/sql/min_usage_period.sql diff --git a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/MinUsagePeriod.java b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/MinUsagePeriod.java new file mode 100644 index 00000000..33185882 --- /dev/null +++ b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/MinUsagePeriod.java @@ -0,0 +1,51 @@ +package org.ruoyi.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.ruoyi.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 最低使用年限表 min_usage_period + * + * @author cass + * @date 2025-09-24 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("min_usage_period") +public class MinUsagePeriod extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 固定资产类别 + */ + private String category; + + /** + * 内容 + */ + private String content; + + /** + * 最低使用年限(年) + */ + private Integer minYears; + + /** + * 国标代码 + */ + private String gbCode; + +} diff --git a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/MinUsagePeriodBo.java b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/MinUsagePeriodBo.java new file mode 100644 index 00000000..eb3c8ab9 --- /dev/null +++ b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/MinUsagePeriodBo.java @@ -0,0 +1,56 @@ +package org.ruoyi.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.ruoyi.common.core.validate.AddGroup; +import org.ruoyi.common.core.validate.EditGroup; +import org.ruoyi.core.domain.BaseEntity; +import org.ruoyi.system.domain.MinUsagePeriod; + +/** + * 最低使用年限表业务对象 min_usage_period + * + * @author cass + * @date 2025-09-24 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = MinUsagePeriod.class, reverseConvertGenerate = false) +public class MinUsagePeriodBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 固定资产类别 + */ + @NotBlank(message = "固定资产类别不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 100, message = "固定资产类别不能超过{max}个字符") + private String category; + + /** + * 内容 + */ + @Size(min = 0, max = 500, message = "内容不能超过{max}个字符") + private String content; + + /** + * 最低使用年限(年) + */ + private Integer minYears; + + /** + * 国标代码 + */ + @NotBlank(message = "国标代码不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 20, message = "国标代码不能超过{max}个字符") + private String gbCode; + +} diff --git a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/MinUsagePeriodImportVo.java b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/MinUsagePeriodImportVo.java new file mode 100644 index 00000000..4ffa7c87 --- /dev/null +++ b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/MinUsagePeriodImportVo.java @@ -0,0 +1,47 @@ +package org.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 最低使用年限表导入VO + * + * @author cass + * @date 2025-09-24 + */ +@Data +@NoArgsConstructor +public class MinUsagePeriodImportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 固定资产类别 + */ + @ExcelProperty(value = "固定资产类别") + private String category; + + /** + * 内容 + */ + @ExcelProperty(value = "内容") + private String content; + + /** + * 最低使用年限(年) + */ + @ExcelProperty(value = "最低使用年限(年)") + private Integer minYears; + + /** + * 国标代码 + */ + @ExcelProperty(value = "国标代码") + private String gbCode; + +} diff --git a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/MinUsagePeriodVo.java b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/MinUsagePeriodVo.java new file mode 100644 index 00000000..806ecf93 --- /dev/null +++ b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/MinUsagePeriodVo.java @@ -0,0 +1,63 @@ +package org.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.ruoyi.system.domain.MinUsagePeriod; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 最低使用年限表视图对象 min_usage_period + * + * @author cass + * @date 2025-09-24 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = MinUsagePeriod.class) +public class MinUsagePeriodVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 固定资产类别 + */ + @ExcelProperty(value = "固定资产类别") + private String category; + + /** + * 内容 + */ + @ExcelProperty(value = "内容") + private String content; + + /** + * 最低使用年限(年) + */ + @ExcelProperty(value = "最低使用年限(年)") + private Integer minYears; + + /** + * 国标代码 + */ + @ExcelProperty(value = "国标代码") + private String gbCode; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/MinUsagePeriodMapper.java b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/MinUsagePeriodMapper.java new file mode 100644 index 00000000..70d89c14 --- /dev/null +++ b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/MinUsagePeriodMapper.java @@ -0,0 +1,17 @@ +package org.ruoyi.system.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.ruoyi.core.mapper.BaseMapperPlus; +import org.ruoyi.system.domain.MinUsagePeriod; +import org.ruoyi.system.domain.vo.MinUsagePeriodVo; + +/** + * 最低使用年限表 数据层 + * + * @author cass + * @date 2025-09-24 + */ +@Mapper +public interface MinUsagePeriodMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/IMinUsagePeriodService.java b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/IMinUsagePeriodService.java new file mode 100644 index 00000000..3a5157ee --- /dev/null +++ b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/IMinUsagePeriodService.java @@ -0,0 +1,60 @@ +package org.ruoyi.system.service; + +import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.system.domain.MinUsagePeriod; +import org.ruoyi.system.domain.bo.MinUsagePeriodBo; +import org.ruoyi.system.domain.vo.MinUsagePeriodVo; +import org.ruoyi.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 最低使用年限表Service接口 + * + * @author cass + * @date 2025-09-24 + */ +public interface IMinUsagePeriodService { + + /** + * 查询最低使用年限表 + */ + MinUsagePeriodVo queryById(Long id); + + /** + * 根据国标代码查询最低使用年限表 + */ + MinUsagePeriod queryByGbCode(String gbCode); + + /** + * 查询最低使用年限表列表 + */ + TableDataInfo queryPageList(MinUsagePeriodBo bo, PageQuery pageQuery); + + /** + * 查询最低使用年限表列表 + */ + List queryList(MinUsagePeriodBo bo); + + /** + * 新增最低使用年限表 + */ + Boolean insertByBo(MinUsagePeriodBo bo); + + /** + * 修改最低使用年限表 + */ + Boolean updateByBo(MinUsagePeriodBo bo); + + /** + * 校验并批量删除最低使用年限表信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 批量导入最低使用年限表数据 + */ + String importData(List dataList, Boolean isUpdateSupport, String operName); + +} diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml index 3f7085d5..bdaf6558 100644 --- a/ruoyi-modules/ruoyi-system/pom.xml +++ b/ruoyi-modules/ruoyi-system/pom.xml @@ -56,6 +56,19 @@ ruoyi-system-api + + + commons-io + commons-io + + + + + org.springframework.boot + spring-boot-starter-test + test + + diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/listener/MinUsagePeriodImportListener.java b/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/listener/MinUsagePeriodImportListener.java new file mode 100644 index 00000000..cee95e20 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/listener/MinUsagePeriodImportListener.java @@ -0,0 +1,107 @@ +package org.ruoyi.system.listener; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import lombok.extern.slf4j.Slf4j; +import org.ruoyi.common.core.utils.SpringUtils; +import org.ruoyi.common.excel.core.ExcelListener; +import org.ruoyi.common.excel.core.ExcelResult; +import org.ruoyi.system.domain.MinUsagePeriod; +import org.ruoyi.system.domain.bo.MinUsagePeriodBo; +import org.ruoyi.system.domain.vo.MinUsagePeriodImportVo; +import org.ruoyi.system.service.IMinUsagePeriodService; + +import java.util.ArrayList; +import java.util.List; + +/** + * 最低使用年限表自定义导入监听器 + * + * @author cass + * @date 2025-09-24 + */ +@Slf4j +public class MinUsagePeriodImportListener extends AnalysisEventListener implements ExcelListener { + + private final IMinUsagePeriodService minUsagePeriodService; + + private final Boolean isUpdateSupport; + + private final String operName; + + private final List list = new ArrayList<>(); + + private int successNum = 0; + private int failureNum = 0; + private final StringBuilder successMsg = new StringBuilder(); + private final StringBuilder failureMsg = new StringBuilder(); + + public MinUsagePeriodImportListener(Boolean isUpdateSupport) { + this.minUsagePeriodService = SpringUtils.getBean(IMinUsagePeriodService.class); + this.isUpdateSupport = isUpdateSupport; + this.operName = "系统"; + } + + @Override + public void invoke(MinUsagePeriodImportVo data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + log.info("所有数据解析完成!"); + // 这里可以添加批量处理逻辑 + for (MinUsagePeriodImportVo data : list) { + try { + // 验证是否存在这个数据 + MinUsagePeriod existData = minUsagePeriodService.queryByGbCode(data.getGbCode()); + if (ObjectUtil.isNull(existData)) { + minUsagePeriodService.insertByBo(BeanUtil.toBean(data, MinUsagePeriodBo.class)); + successNum++; + successMsg.append("
" + successNum + "、国标代码 " + data.getGbCode() + " 导入成功"); + } else if (isUpdateSupport) { + BeanUtil.copyProperties(data, existData); + minUsagePeriodService.updateByBo(BeanUtil.toBean(existData, MinUsagePeriodBo.class)); + successNum++; + successMsg.append("
" + successNum + "、国标代码 " + data.getGbCode() + " 更新成功"); + } else { + failureNum++; + failureMsg.append("
" + failureNum + "、国标代码 " + data.getGbCode() + " 已存在"); + } + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、国标代码 " + data.getGbCode() + " 导入失败:"; + failureMsg.append(msg + e.getMessage()); + log.error(msg, e); + } + } + } + + @Override + public ExcelResult getExcelResult() { + return new ExcelResult() { + @Override + public List getList() { + return list; + } + + @Override + public List getErrorList() { + return new ArrayList<>(); + } + + @Override + public String getAnalysis() { + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + return failureMsg.toString(); + } else { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + return successMsg.toString(); + } + } + }; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/MinUsagePeriodServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/MinUsagePeriodServiceImpl.java new file mode 100644 index 00000000..2e106ec7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/MinUsagePeriodServiceImpl.java @@ -0,0 +1,183 @@ +package org.ruoyi.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.ruoyi.common.core.utils.MapstructUtils; +import org.ruoyi.common.core.utils.StringUtils; +import org.ruoyi.core.page.PageQuery; +import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.system.domain.MinUsagePeriod; +import org.ruoyi.system.domain.bo.MinUsagePeriodBo; +import org.ruoyi.system.domain.vo.MinUsagePeriodVo; +import org.ruoyi.system.mapper.MinUsagePeriodMapper; +import org.ruoyi.system.service.IMinUsagePeriodService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 最低使用年限表Service业务层处理 + * + * @author cass + * @date 2025-09-24 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class MinUsagePeriodServiceImpl implements IMinUsagePeriodService { + + private final MinUsagePeriodMapper baseMapper; + + /** + * 查询最低使用年限表 + */ + @Override + public MinUsagePeriodVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 根据国标代码查询最低使用年限表 + */ + @Override + public MinUsagePeriod queryByGbCode(String gbCode) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(MinUsagePeriod::getGbCode, gbCode); + return baseMapper.selectOne(lqw); + } + + /** + * 查询最低使用年限表列表 + */ + @Override + public TableDataInfo queryPageList(MinUsagePeriodBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询最低使用年限表列表 + */ + @Override + public List queryList(MinUsagePeriodBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(MinUsagePeriodBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getCategory()), MinUsagePeriod::getCategory, bo.getCategory()); + lqw.like(StringUtils.isNotBlank(bo.getContent()), MinUsagePeriod::getContent, bo.getContent()); + lqw.eq(ObjectUtil.isNotNull(bo.getMinYears()), MinUsagePeriod::getMinYears, bo.getMinYears()); + lqw.eq(StringUtils.isNotBlank(bo.getGbCode()), MinUsagePeriod::getGbCode, bo.getGbCode()); + return lqw; + } + + /** + * 新增最低使用年限表 + */ + @Override + public Boolean insertByBo(MinUsagePeriodBo bo) { + MinUsagePeriod add = MapstructUtils.convert(bo, MinUsagePeriod.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改最低使用年限表 + */ + @Override + public Boolean updateByBo(MinUsagePeriodBo bo) { + MinUsagePeriod update = MapstructUtils.convert(bo, MinUsagePeriod.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(MinUsagePeriod entity) { + // 校验国标代码唯一性 + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(MinUsagePeriod::getGbCode, entity.getGbCode()); + if (ObjectUtil.isNotNull(entity.getId())) { + lqw.ne(MinUsagePeriod::getId, entity.getId()); + } + boolean exists = baseMapper.exists(lqw); + if (exists) { + throw new RuntimeException("国标代码已存在"); + } + } + + /** + * 批量删除最低使用年限表 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 批量导入最低使用年限表数据 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public String importData(List dataList, Boolean isUpdateSupport, String operName) { + if (ObjectUtil.isNull(dataList) || dataList.size() == 0) { + throw new RuntimeException("导入数据不能为空!"); + } + int successNum = 0; + int failureNum = 0; + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + for (MinUsagePeriodVo data : dataList) { + try { + // 验证是否存在这个数据 + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(MinUsagePeriod::getGbCode, data.getGbCode()); + MinUsagePeriod existData = baseMapper.selectOne(lqw); + if (ObjectUtil.isNull(existData)) { + MinUsagePeriod addData = MapstructUtils.convert(data, MinUsagePeriod.class); + baseMapper.insert(addData); + successNum++; + successMsg.append("
" + successNum + "、国标代码 " + data.getGbCode() + " 导入成功"); + } else if (isUpdateSupport) { + MapstructUtils.convert(data, existData); + baseMapper.updateById(existData); + successNum++; + successMsg.append("
" + successNum + "、国标代码 " + data.getGbCode() + " 更新成功"); + } else { + failureNum++; + failureMsg.append("
" + failureNum + "、国标代码 " + data.getGbCode() + " 已存在"); + } + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、国标代码 " + data.getGbCode() + " 导入失败:"; + failureMsg.append(msg + e.getMessage()); + log.error(msg, e); + } + } + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new RuntimeException(failureMsg.toString()); + } else { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/DatabaseImportTest.java b/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/DatabaseImportTest.java new file mode 100644 index 00000000..b646cf43 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/DatabaseImportTest.java @@ -0,0 +1,261 @@ +package org.ruoyi.system.service; + +import com.alibaba.excel.EasyExcel; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.ruoyi.system.domain.MinUsagePeriod; +import org.ruoyi.system.domain.vo.MinUsagePeriodImportVo; +import org.ruoyi.system.listener.MinUsagePeriodImportListener; +import org.ruoyi.system.mapper.MinUsagePeriodMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.List; + +/** + * 数据库导入测试 + * + * @author cass + * @date 2025-09-24 + */ +@Slf4j +@SpringBootTest(classes = {org.ruoyi.RuoYiAIApplication.class}) +@ActiveProfiles("test") +public class DatabaseImportTest { + + @Autowired + private MinUsagePeriodMapper minUsagePeriodMapper; + + @Autowired + private IMinUsagePeriodService minUsagePeriodService; + + /** + * Excel文件路径 + */ + private static final String EXCEL_FILE_PATH = "E:/z. WorkSpace/ruoyi-ai/workspace/教育部直属高校固定资产最低使用年限表.xlsx"; + + /** + * 测试Excel数据导入到数据库 + */ + @Test + @Transactional + public void testExcelImportToDatabase() { + try { + log.info("=== 开始Excel数据导入到数据库测试 ==="); + + // 1. 清空测试数据 + log.info("1. 清空测试数据..."); + minUsagePeriodMapper.delete(null); + log.info(" 清空完成"); + + // 2. 读取Excel文件 + log.info("2. 读取Excel文件..."); + File excelFile = new File(EXCEL_FILE_PATH); + if (!excelFile.exists()) { + log.error("Excel文件不存在: {}", EXCEL_FILE_PATH); + return; + } + + List dataList; + try (InputStream inputStream = new FileInputStream(excelFile)) { + dataList = EasyExcel.read(inputStream) + .head(MinUsagePeriodImportVo.class) + .sheet() + .doReadSync(); + } + log.info(" 读取到 {} 条数据", dataList.size()); + + // 3. 处理数据(填充固定资产类别) + log.info("3. 处理数据..."); + processData(dataList); + log.info(" 数据处理完成"); + + // 4. 批量插入数据库 + log.info("4. 批量插入数据库..."); + int successCount = 0; + int failCount = 0; + + for (MinUsagePeriodImportVo importVo : dataList) { + try { + // 转换为实体对象 + MinUsagePeriod entity = convertToEntity(importVo); + + // 插入数据库 + minUsagePeriodMapper.insert(entity); + successCount++; + + if (successCount <= 5) { + log.info(" 插入成功: {} - {}", entity.getContent(), entity.getGbCode()); + } + } catch (Exception e) { + failCount++; + log.error(" 插入失败: {} - {}", importVo.getContent(), importVo.getGbCode(), e); + } + } + + log.info(" 插入完成: 成功 {} 条, 失败 {} 条", successCount, failCount); + + // 5. 验证数据库中的数据 + log.info("5. 验证数据库中的数据..."); + List dbData = minUsagePeriodMapper.selectList(null); + log.info(" 数据库中共有 {} 条记录", dbData.size()); + + // 显示前10条数据 + for (int i = 0; i < Math.min(10, dbData.size()); i++) { + MinUsagePeriod data = dbData.get(i); + log.info(" 第{}条: 类别={}, 内容={}, 年限={}, 国标代码={}", + i + 1, data.getCategory(), data.getContent(), data.getMinYears(), data.getGbCode()); + } + + // 6. 验证数据完整性 + log.info("6. 验证数据完整性..."); + validateDatabaseData(dbData); + + log.info("=== Excel数据导入到数据库测试完成 ==="); + + } catch (Exception e) { + log.error("Excel数据导入到数据库测试失败", e); + } + } + + /** + * 测试使用Service层导入数据 + */ + @Test + @Transactional + public void testServiceImportData() { + try { + log.info("=== 开始Service层导入数据测试 ==="); + + // 1. 清空测试数据 + log.info("1. 清空测试数据..."); + minUsagePeriodMapper.delete(null); + log.info(" 清空完成"); + + // 2. 使用Service层导入数据 + log.info("2. 使用Service层导入数据..."); + File excelFile = new File(EXCEL_FILE_PATH); + if (!excelFile.exists()) { + log.error("Excel文件不存在: {}", EXCEL_FILE_PATH); + return; + } + + try (InputStream inputStream = new FileInputStream(excelFile)) { + // 使用自定义监听器导入数据 + MinUsagePeriodImportListener listener = new MinUsagePeriodImportListener(true); + + EasyExcel.read(inputStream) + .head(MinUsagePeriodImportVo.class) + .registerReadListener(listener) + .sheet() + .doRead(); + + log.info(" Service层导入完成"); + } + + // 3. 验证数据库中的数据 + log.info("3. 验证数据库中的数据..."); + List dbData = minUsagePeriodMapper.selectList(null); + log.info(" 数据库中共有 {} 条记录", dbData.size()); + + // 显示前10条数据 + for (int i = 0; i < Math.min(10, dbData.size()); i++) { + MinUsagePeriod data = dbData.get(i); + log.info(" 第{}条: 类别={}, 内容={}, 年限={}, 国标代码={}", + i + 1, data.getCategory(), data.getContent(), data.getMinYears(), data.getGbCode()); + } + + log.info("=== Service层导入数据测试完成 ==="); + + } catch (Exception e) { + log.error("Service层导入数据测试失败", e); + } + } + + /** + * 处理数据,填充固定资产类别 + */ + private void processData(List dataList) { + String currentCategory = null; + + for (MinUsagePeriodImportVo data : dataList) { + // 如果当前行有固定资产类别,更新当前类别 + if (data.getCategory() != null && !data.getCategory().trim().isEmpty()) { + currentCategory = data.getCategory().trim(); + } + + // 如果当前行没有固定资产类别,使用当前类别 + if (data.getCategory() == null || data.getCategory().trim().isEmpty()) { + data.setCategory(currentCategory); + } + } + } + + /** + * 转换为实体对象 + */ + private MinUsagePeriod convertToEntity(MinUsagePeriodImportVo importVo) { + MinUsagePeriod entity = new MinUsagePeriod(); + entity.setCategory(importVo.getCategory()); + entity.setContent(importVo.getContent()); + entity.setMinYears(importVo.getMinYears()); + entity.setGbCode(importVo.getGbCode()); + return entity; + } + + /** + * 验证数据库中的数据 + */ + private void validateDatabaseData(List dbData) { + log.info(" 数据验证结果:"); + log.info(" - 总记录数: {}", dbData.size()); + + // 统计各类别的数量 + long categoryCount = dbData.stream() + .filter(data -> data.getCategory() != null && !data.getCategory().trim().isEmpty()) + .count(); + log.info(" - 有固定资产类别的记录: {}/{}", categoryCount, dbData.size()); + + // 统计各年限的数量 + long yearsCount = dbData.stream() + .filter(data -> data.getMinYears() != null) + .count(); + log.info(" - 有最低使用年限的记录: {}/{}", yearsCount, dbData.size()); + + // 统计各国标代码的数量 + long gbCodeCount = dbData.stream() + .filter(data -> data.getGbCode() != null && !data.getGbCode().trim().isEmpty()) + .count(); + log.info(" - 有国标代码的记录: {}/{}", gbCodeCount, dbData.size()); + + // 检查重复的国标代码 + long uniqueGbCodeCount = dbData.stream() + .filter(data -> data.getGbCode() != null && !data.getGbCode().trim().isEmpty()) + .map(MinUsagePeriod::getGbCode) + .distinct() + .count(); + log.info(" - 唯一国标代码数量: {}", uniqueGbCodeCount); + + if (uniqueGbCodeCount != gbCodeCount) { + log.warn(" - 发现重复的国标代码!"); + } else { + log.info(" - 国标代码唯一性检查通过"); + } + + // 数据质量评估 + if (categoryCount == dbData.size() && + yearsCount == dbData.size() && + gbCodeCount == dbData.size()) { + log.info(" - 数据质量: 优秀 (所有字段都完整)"); + } else if (yearsCount == dbData.size() && gbCodeCount == dbData.size()) { + log.info(" - 数据质量: 良好 (核心字段完整)"); + } else { + log.warn(" - 数据质量: 需要改进 (存在缺失字段)"); + } + } +} diff --git a/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/DatabaseInitTest.java b/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/DatabaseInitTest.java new file mode 100644 index 00000000..06f476bb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/DatabaseInitTest.java @@ -0,0 +1,114 @@ +package org.ruoyi.system.service; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.ruoyi.system.mapper.MinUsagePeriodMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.Statement; + +/** + * 数据库初始化测试 + * + * @author cass + * @date 2025-09-24 + */ +@Slf4j +@SpringBootTest(classes = {org.ruoyi.RuoYiAIApplication.class}) +@ActiveProfiles("test") +public class DatabaseInitTest { + + @Autowired + private MinUsagePeriodMapper minUsagePeriodMapper; + + /** + * 测试数据库连接和表创建 + */ + @Test + public void testDatabaseConnectionAndTableCreation() { + try { + log.info("=== 开始数据库连接和表创建测试 ==="); + + // 1. 测试数据库连接 + log.info("1. 测试数据库连接..."); + String url = "jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8"; + String username = "root"; + String password = "666666"; + + try (Connection connection = DriverManager.getConnection(url, username, password)) { + log.info(" 数据库连接成功"); + + // 2. 检查表是否存在 + log.info("2. 检查min_usage_period表是否存在..."); + boolean tableExists = checkTableExists(connection); + + if (!tableExists) { + log.info(" 表不存在,开始创建表..."); + createTable(connection); + log.info(" 表创建完成"); + } else { + log.info(" 表已存在"); + } + + // 3. 测试Mapper + log.info("3. 测试Mapper..."); + try { + Long count = minUsagePeriodMapper.selectCount(null); + log.info(" 当前表中有 {} 条记录", count); + } catch (Exception e) { + log.error(" Mapper测试失败", e); + } + + } + + log.info("=== 数据库连接和表创建测试完成 ==="); + + } catch (Exception e) { + log.error("数据库连接和表创建测试失败", e); + } + } + + /** + * 检查表是否存在 + */ + private boolean checkTableExists(Connection connection) { + try (Statement statement = connection.createStatement()) { + statement.executeQuery("SELECT 1 FROM min_usage_period LIMIT 1"); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * 创建表 + */ + private void createTable(Connection connection) { + String createTableSql = """ + CREATE TABLE `min_usage_period` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `category` varchar(100) NOT NULL COMMENT '固定资产类别', + `content` varchar(200) NOT NULL COMMENT '内容', + `min_years` int(11) NOT NULL COMMENT '最低使用年限(年)', + `gb_code` varchar(20) NOT NULL COMMENT '国标代码', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_by` varchar(64) DEFAULT '' COMMENT '创建者', + `update_by` varchar(64) DEFAULT '' COMMENT '更新者', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_gb_code` (`gb_code`), + KEY `idx_category` (`category`), + KEY `idx_content` (`content`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='最低使用年限表' + """; + + try (Statement statement = connection.createStatement()) { + statement.execute(createTableSql); + } + } +} diff --git a/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/ExcelImportSimpleTest.java b/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/ExcelImportSimpleTest.java new file mode 100644 index 00000000..569c7bd9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/ExcelImportSimpleTest.java @@ -0,0 +1,172 @@ +package org.ruoyi.system.service; + +import com.alibaba.excel.EasyExcel; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.ruoyi.system.domain.vo.MinUsagePeriodImportVo; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.List; + +/** + * 简单的Excel导入测试(不依赖Spring Boot) + * + * @author cass + * @date 2025-09-24 + */ +@Slf4j +public class ExcelImportSimpleTest { + + /** + * Excel文件路径 + */ + private static final String EXCEL_FILE_PATH = "E:/z. WorkSpace/ruoyi-ai/workspace/教育部直属高校固定资产最低使用年限表.xlsx"; + + public static void main(String[] args) { + ExcelImportSimpleTest test = new ExcelImportSimpleTest(); + test.testExcelFileRead(); + } + + /** + * 测试Excel文件读取和解析 + */ + @Test + public void testExcelFileRead() { + try { + File excelFile = new File(EXCEL_FILE_PATH); + + if (!excelFile.exists()) { + log.error("Excel文件不存在: {}", EXCEL_FILE_PATH); + return; + } + + log.info("=== Excel文件信息 ==="); + log.info("文件路径: {}", excelFile.getAbsolutePath()); + log.info("文件大小: {} bytes", excelFile.length()); + log.info("文件是否存在: {}", excelFile.exists()); + log.info("文件是否可读: {}", excelFile.canRead()); + + // 使用EasyExcel直接读取 + try (InputStream inputStream = new FileInputStream(excelFile)) { + List dataList = EasyExcel.read(inputStream) + .head(MinUsagePeriodImportVo.class) + .sheet() + .doReadSync(); + + log.info("=== 读取结果 ==="); + log.info("EasyExcel直接读取到 {} 条数据", dataList.size()); + + // 打印前10条数据 + for (int i = 0; i < Math.min(10, dataList.size()); i++) { + MinUsagePeriodImportVo data = dataList.get(i); + log.info("第{}条: 类别={}, 内容={}, 年限={}, 国标代码={}", + i + 1, data.getCategory(), data.getContent(), data.getMinYears(), data.getGbCode()); + } + + // 验证数据完整性 + validateData(dataList); + + } + + } catch (Exception e) { + log.error("Excel文件读取测试失败", e); + } + } + + /** + * 验证数据完整性 + */ + private void validateData(List dataList) { + log.info("=== 数据验证结果 ==="); + + int validCategoryCount = 0; + int validContentCount = 0; + int validMinYearsCount = 0; + int validGbCodeCount = 0; + + for (MinUsagePeriodImportVo data : dataList) { + if (data.getCategory() != null && !data.getCategory().trim().isEmpty()) { + validCategoryCount++; + } + if (data.getContent() != null && !data.getContent().trim().isEmpty()) { + validContentCount++; + } + if (data.getMinYears() != null) { + validMinYearsCount++; + } + if (data.getGbCode() != null && !data.getGbCode().trim().isEmpty()) { + validGbCodeCount++; + } + } + + log.info("总行数: {}", dataList.size()); + log.info("有效固定资产类别: {}/{}", validCategoryCount, dataList.size()); + log.info("有效内容: {}/{}", validContentCount, dataList.size()); + log.info("有效最低使用年限: {}/{}", validMinYearsCount, dataList.size()); + log.info("有效国标代码: {}/{}", validGbCodeCount, dataList.size()); + + // 检查重复的国标代码 + long uniqueGbCodeCount = dataList.stream() + .filter(data -> data.getGbCode() != null && !data.getGbCode().trim().isEmpty()) + .map(MinUsagePeriodImportVo::getGbCode) + .distinct() + .count(); + + log.info("唯一国标代码数量: {}", uniqueGbCodeCount); + + if (uniqueGbCodeCount != validGbCodeCount) { + log.warn("发现重复的国标代码!"); + } + + // 检查数据质量 + if (validCategoryCount == dataList.size() && + validContentCount == dataList.size() && + validMinYearsCount == dataList.size() && + validGbCodeCount == dataList.size()) { + log.info("✓ 数据质量检查通过,所有字段都完整"); + } else { + log.warn("✗ 数据质量检查未通过,存在缺失字段"); + } + } + + /** + * 测试Excel文件格式 + */ + @Test + public void testExcelFormat() { + try { + File excelFile = new File(EXCEL_FILE_PATH); + + if (!excelFile.exists()) { + log.error("Excel文件不存在: {}", EXCEL_FILE_PATH); + return; + } + + log.info("=== 开始Excel格式测试 ==="); + + try (InputStream inputStream = new FileInputStream(excelFile)) { + // 测试读取第一行(标题行) + List dataList = EasyExcel.read(inputStream) + .head(MinUsagePeriodImportVo.class) + .sheet() + .doReadSync(); + + if (!dataList.isEmpty()) { + MinUsagePeriodImportVo firstData = dataList.get(0); + log.info("第一行数据示例:"); + log.info("- 固定资产类别: {}", firstData.getCategory()); + log.info("- 内容: {}", firstData.getContent()); + log.info("- 最低使用年限: {}", firstData.getMinYears()); + log.info("- 国标代码: {}", firstData.getGbCode()); + } + + log.info("Excel格式测试完成,共读取 {} 行数据", dataList.size()); + } + + } catch (Exception e) { + log.error("Excel格式测试失败", e); + } + } +} diff --git a/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/SimpleDatabaseTest.java b/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/SimpleDatabaseTest.java new file mode 100644 index 00000000..53d903f5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/SimpleDatabaseTest.java @@ -0,0 +1,233 @@ +package org.ruoyi.system.service; + +import com.alibaba.excel.EasyExcel; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.ruoyi.system.domain.MinUsagePeriod; +import org.ruoyi.system.domain.vo.MinUsagePeriodImportVo; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.Statement; +import java.util.List; + +/** + * 简单数据库测试(不依赖Spring Boot) + * + * @author cass + * @date 2025-09-24 + */ +@Slf4j +public class SimpleDatabaseTest { + + /** + * Excel文件路径 + */ + private static final String EXCEL_FILE_PATH = "E:/z. WorkSpace/ruoyi-ai/workspace/教育部直属高校固定资产最低使用年限表.xlsx"; + + /** + * 数据库连接信息 + */ + private static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8"; + private static final String DB_USERNAME = "root"; + private static final String DB_PASSWORD = "666666"; + + /** + * 测试Excel数据导入到数据库 + */ + @Test + public void testExcelImportToDatabase() { + try { + log.info("=== 开始Excel数据导入到数据库测试 ==="); + + // 1. 连接数据库 + log.info("1. 连接数据库..."); + try (Connection connection = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD)) { + log.info(" 数据库连接成功"); + + // 2. 创建表(如果不存在) + log.info("2. 创建表(如果不存在)..."); + createTableIfNotExists(connection); + log.info(" 表创建完成"); + + // 3. 清空测试数据 + log.info("3. 清空测试数据..."); + clearTestData(connection); + log.info(" 清空完成"); + + // 4. 读取Excel文件 + log.info("4. 读取Excel文件..."); + List dataList = readExcelFile(); + log.info(" 读取到 {} 条数据", dataList.size()); + + // 5. 处理数据(填充固定资产类别) + log.info("5. 处理数据..."); + processData(dataList); + log.info(" 数据处理完成"); + + // 6. 批量插入数据库 + log.info("6. 批量插入数据库..."); + int successCount = insertDataToDatabase(connection, dataList); + log.info(" 插入完成: 成功 {} 条", successCount); + + // 7. 验证数据库中的数据 + log.info("7. 验证数据库中的数据..."); + int dbCount = getDatabaseRecordCount(connection); + log.info(" 数据库中共有 {} 条记录", dbCount); + + // 8. 显示部分数据 + log.info("8. 显示部分数据..."); + showSampleData(connection); + + } + + log.info("=== Excel数据导入到数据库测试完成 ==="); + + } catch (Exception e) { + log.error("Excel数据导入到数据库测试失败", e); + } + } + + /** + * 创建表(如果不存在) + */ + private void createTableIfNotExists(Connection connection) throws Exception { + String createTableSql = """ + CREATE TABLE IF NOT EXISTS `min_usage_period` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `category` varchar(100) NOT NULL COMMENT '固定资产类别', + `content` varchar(200) NOT NULL COMMENT '内容', + `min_years` int(11) NOT NULL COMMENT '最低使用年限(年)', + `gb_code` varchar(20) NOT NULL COMMENT '国标代码', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_by` varchar(64) DEFAULT '' COMMENT '创建者', + `update_by` varchar(64) DEFAULT '' COMMENT '更新者', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_gb_code` (`gb_code`), + KEY `idx_category` (`category`), + KEY `idx_content` (`content`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='最低使用年限表' + """; + + try (Statement statement = connection.createStatement()) { + statement.execute(createTableSql); + } + } + + /** + * 清空测试数据 + */ + private void clearTestData(Connection connection) throws Exception { + String deleteSql = "DELETE FROM min_usage_period"; + try (Statement statement = connection.createStatement()) { + statement.executeUpdate(deleteSql); + } + } + + /** + * 读取Excel文件 + */ + private List readExcelFile() throws Exception { + File excelFile = new File(EXCEL_FILE_PATH); + if (!excelFile.exists()) { + throw new RuntimeException("Excel文件不存在: " + EXCEL_FILE_PATH); + } + + try (InputStream inputStream = new FileInputStream(excelFile)) { + return EasyExcel.read(inputStream) + .head(MinUsagePeriodImportVo.class) + .sheet() + .doReadSync(); + } + } + + /** + * 处理数据,填充固定资产类别 + */ + private void processData(List dataList) { + String currentCategory = null; + + for (MinUsagePeriodImportVo data : dataList) { + // 如果当前行有固定资产类别,更新当前类别 + if (data.getCategory() != null && !data.getCategory().trim().isEmpty()) { + currentCategory = data.getCategory().trim(); + } + + // 如果当前行没有固定资产类别,使用当前类别 + if (data.getCategory() == null || data.getCategory().trim().isEmpty()) { + data.setCategory(currentCategory); + } + } + } + + /** + * 插入数据到数据库 + */ + private int insertDataToDatabase(Connection connection, List dataList) throws Exception { + String insertSql = "INSERT INTO min_usage_period (category, content, min_years, gb_code) VALUES (?, ?, ?, ?)"; + + int successCount = 0; + try (PreparedStatement statement = connection.prepareStatement(insertSql)) { + for (MinUsagePeriodImportVo data : dataList) { + try { + statement.setString(1, data.getCategory()); + statement.setString(2, data.getContent()); + statement.setInt(3, data.getMinYears()); + statement.setString(4, data.getGbCode()); + + statement.executeUpdate(); + successCount++; + + if (successCount <= 5) { + log.info(" 插入成功: {} - {}", data.getContent(), data.getGbCode()); + } + } catch (Exception e) { + log.error(" 插入失败: {} - {}", data.getContent(), data.getGbCode(), e); + } + } + } + + return successCount; + } + + /** + * 获取数据库记录数 + */ + private int getDatabaseRecordCount(Connection connection) throws Exception { + String countSql = "SELECT COUNT(*) FROM min_usage_period"; + try (Statement statement = connection.createStatement()) { + var resultSet = statement.executeQuery(countSql); + if (resultSet.next()) { + return resultSet.getInt(1); + } + } + return 0; + } + + /** + * 显示部分数据 + */ + private void showSampleData(Connection connection) throws Exception { + String selectSql = "SELECT * FROM min_usage_period LIMIT 10"; + try (Statement statement = connection.createStatement()) { + var resultSet = statement.executeQuery(selectSql); + int count = 0; + while (resultSet.next() && count < 10) { + count++; + String category = resultSet.getString("category"); + String content = resultSet.getString("content"); + int minYears = resultSet.getInt("min_years"); + String gbCode = resultSet.getString("gb_code"); + + log.info(" 第{}条: 类别={}, 内容={}, 年限={}, 国标代码={}", + count, category, content, minYears, gbCode); + } + } + } +} diff --git a/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/SimpleExcelImportTest.java b/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/SimpleExcelImportTest.java new file mode 100644 index 00000000..e5b5db85 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/test/java/org/ruoyi/system/service/SimpleExcelImportTest.java @@ -0,0 +1,169 @@ +package org.ruoyi.system.service; + +import com.alibaba.excel.EasyExcel; +import lombok.extern.slf4j.Slf4j; +import org.ruoyi.system.domain.vo.MinUsagePeriodImportVo; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.List; + +/** + * 简单的Excel导入测试(不依赖Spring Boot) + * + * @author cass + * @date 2025-09-24 + */ +@Slf4j +public class SimpleExcelImportTest { + + /** + * 测试Excel文件读取 + */ + public static void main(String[] args) { + SimpleExcelImportTest test = new SimpleExcelImportTest(); + test.testExcelFileRead(); + } + + /** + * 测试Excel文件读取和解析 + */ + public void testExcelFileRead() { + try { + String excelPath = "workspace/教育部直属高校固定资产最低使用年限表.xlsx"; + File excelFile = new File(excelPath); + + if (!excelFile.exists()) { + log.error("Excel文件不存在: {}", excelPath); + return; + } + + log.info("Excel文件信息:"); + log.info("文件路径: {}", excelFile.getAbsolutePath()); + log.info("文件大小: {} bytes", excelFile.length()); + log.info("文件是否存在: {}", excelFile.exists()); + log.info("文件是否可读: {}", excelFile.canRead()); + + // 使用EasyExcel直接读取 + try (InputStream inputStream = new FileInputStream(excelFile)) { + List dataList = EasyExcel.read(inputStream) + .head(MinUsagePeriodImportVo.class) + .sheet() + .doReadSync(); + + log.info("EasyExcel直接读取到 {} 条数据", dataList.size()); + + // 打印所有数据 + for (int i = 0; i < dataList.size(); i++) { + MinUsagePeriodImportVo data = dataList.get(i); + log.info("第{}条: 类别={}, 内容={}, 年限={}, 国标代码={}", + i + 1, data.getCategory(), data.getContent(), data.getMinYears(), data.getGbCode()); + } + + // 验证数据完整性 + validateData(dataList); + + } + + } catch (Exception e) { + log.error("Excel文件读取测试失败", e); + } + } + + /** + * 验证数据完整性 + */ + private void validateData(List dataList) { + log.info("开始数据验证..."); + + int validCategoryCount = 0; + int validContentCount = 0; + int validMinYearsCount = 0; + int validGbCodeCount = 0; + + for (MinUsagePeriodImportVo data : dataList) { + if (data.getCategory() != null && !data.getCategory().trim().isEmpty()) { + validCategoryCount++; + } + if (data.getContent() != null && !data.getContent().trim().isEmpty()) { + validContentCount++; + } + if (data.getMinYears() != null) { + validMinYearsCount++; + } + if (data.getGbCode() != null && !data.getGbCode().trim().isEmpty()) { + validGbCodeCount++; + } + } + + log.info("数据验证结果:"); + log.info("- 总行数: {}", dataList.size()); + log.info("- 有效固定资产类别: {}/{}", validCategoryCount, dataList.size()); + log.info("- 有效内容: {}/{}", validContentCount, dataList.size()); + log.info("- 有效最低使用年限: {}/{}", validMinYearsCount, dataList.size()); + log.info("- 有效国标代码: {}/{}", validGbCodeCount, dataList.size()); + + // 检查重复的国标代码 + long uniqueGbCodeCount = dataList.stream() + .filter(data -> data.getGbCode() != null && !data.getGbCode().trim().isEmpty()) + .map(MinUsagePeriodImportVo::getGbCode) + .distinct() + .count(); + + log.info("- 唯一国标代码数量: {}", uniqueGbCodeCount); + + if (uniqueGbCodeCount != validGbCodeCount) { + log.warn("发现重复的国标代码!"); + } + + // 检查数据质量 + if (validCategoryCount == dataList.size() && + validContentCount == dataList.size() && + validMinYearsCount == dataList.size() && + validGbCodeCount == dataList.size()) { + log.info("✓ 数据质量检查通过,所有字段都完整"); + } else { + log.warn("✗ 数据质量检查未通过,存在缺失字段"); + } + } + + /** + * 测试Excel文件格式 + */ + public void testExcelFormat() { + try { + String excelPath = "workspace/教育部直属高校固定资产最低使用年限表.xlsx"; + File excelFile = new File(excelPath); + + if (!excelFile.exists()) { + log.error("Excel文件不存在: {}", excelPath); + return; + } + + log.info("开始Excel格式测试..."); + + try (InputStream inputStream = new FileInputStream(excelFile)) { + // 测试读取第一行(标题行) + List dataList = EasyExcel.read(inputStream) + .head(MinUsagePeriodImportVo.class) + .sheet() + .doReadSync(); + + if (!dataList.isEmpty()) { + MinUsagePeriodImportVo firstData = dataList.get(0); + log.info("第一行数据示例:"); + log.info("- 固定资产类别: {}", firstData.getCategory()); + log.info("- 内容: {}", firstData.getContent()); + log.info("- 最低使用年限: {}", firstData.getMinYears()); + log.info("- 国标代码: {}", firstData.getGbCode()); + } + + log.info("Excel格式测试完成,共读取 {} 行数据", dataList.size()); + } + + } catch (Exception e) { + log.error("Excel格式测试失败", e); + } + } +} diff --git a/script/sql/min_usage_period.sql b/script/sql/min_usage_period.sql new file mode 100644 index 00000000..6b8399f8 --- /dev/null +++ b/script/sql/min_usage_period.sql @@ -0,0 +1,17 @@ +-- 最低使用年限表 +CREATE TABLE `min_usage_period` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `category` varchar(100) NOT NULL COMMENT '固定资产类别', + `content` varchar(200) NOT NULL COMMENT '内容', + `min_years` int(11) NOT NULL COMMENT '最低使用年限(年)', + `gb_code` varchar(20) NOT NULL COMMENT '国标代码', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_by` varchar(64) DEFAULT '' COMMENT '创建者', + `update_by` varchar(64) DEFAULT '' COMMENT '更新者', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_gb_code` (`gb_code`), + KEY `idx_category` (`category`), + KEY `idx_content` (`content`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='最低使用年限表'; \ No newline at end of file