mirror of
https://gitcode.com/ageerle/ruoyi-ai.git
synced 2026-04-06 16:27:32 +00:00
13
pom.xml
13
pom.xml
@@ -42,6 +42,8 @@
|
|||||||
<bouncycastle.version>1.72</bouncycastle.version>
|
<bouncycastle.version>1.72</bouncycastle.version>
|
||||||
<!-- Apache Commons Compress 版本 -->
|
<!-- Apache Commons Compress 版本 -->
|
||||||
<commons-compress.version>1.26.2</commons-compress.version>
|
<commons-compress.version>1.26.2</commons-compress.version>
|
||||||
|
<!-- Apache Commons IO 版本 -->
|
||||||
|
<commons-io.version>2.17.0</commons-io.version>
|
||||||
<!-- 离线IP地址定位库 -->
|
<!-- 离线IP地址定位库 -->
|
||||||
<ip2region.version>2.7.0</ip2region.version>
|
<ip2region.version>2.7.0</ip2region.version>
|
||||||
<!-- OSS 配置 -->
|
<!-- OSS 配置 -->
|
||||||
@@ -53,8 +55,8 @@
|
|||||||
<!-- 插件版本 -->
|
<!-- 插件版本 -->
|
||||||
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
|
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
|
||||||
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
|
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
|
||||||
<maven-compiler-plugin.verison>3.11.0</maven-compiler-plugin.verison>
|
<maven-compiler-plugin.verison>3.14.0</maven-compiler-plugin.verison>
|
||||||
<maven-surefire-plugin.version>3.0.0</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>3.5.4</maven-surefire-plugin.version>
|
||||||
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
|
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
@@ -292,6 +294,13 @@
|
|||||||
<version>${commons-compress.version}</version>
|
<version>${commons-compress.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Apache Commons IO -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>${commons-io.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.linpeilie</groupId>
|
<groupId>io.github.linpeilie</groupId>
|
||||||
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
|
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package org.ruoyi.system.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.ruoyi.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高等学校固定资产分类与代码对象 asset_classification
|
||||||
|
*
|
||||||
|
* @author cass
|
||||||
|
* @date 2025-09-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("asset_classification")
|
||||||
|
public class AssetClassification extends BaseEntity {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@TableId(value = "id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类代码
|
||||||
|
*/
|
||||||
|
private String classificationCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类名称
|
||||||
|
*/
|
||||||
|
private String classificationName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国标名称
|
||||||
|
*/
|
||||||
|
private String gbName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package org.ruoyi.system.domain.bo;
|
||||||
|
|
||||||
|
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 jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高等学校固定资产分类与代码业务对象 asset_classification
|
||||||
|
*
|
||||||
|
* @author cass
|
||||||
|
* @date 2025-09-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class AssetClassificationBo extends BaseEntity {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@NotNull(message = "主键ID不能为空", groups = {EditGroup.class})
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类代码
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "分类代码不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||||
|
private String classificationCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类名称
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "分类名称不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||||
|
private String classificationName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国标名称
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "国标名称不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||||
|
private String gbName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package org.ruoyi.system.domain.vo;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高等学校固定资产分类与代码导入视图对象
|
||||||
|
*
|
||||||
|
* @author cass
|
||||||
|
* @date 2025-09-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AssetClassificationImportVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类代码
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "分类代码")
|
||||||
|
private String classificationCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类名称
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "分类名称")
|
||||||
|
private String classificationName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国标名称
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "国标名称")
|
||||||
|
private String gbName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package org.ruoyi.system.domain.vo;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.ruoyi.common.excel.annotation.ExcelDictFormat;
|
||||||
|
import org.ruoyi.common.excel.convert.ExcelDictConvert;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高等学校固定资产分类与代码视图对象 asset_classification
|
||||||
|
*
|
||||||
|
* @author cass
|
||||||
|
* @date 2025-09-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ExcelIgnoreUnannotated
|
||||||
|
public class AssetClassificationVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "主键ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类代码
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "分类代码")
|
||||||
|
private String classificationCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类名称
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "分类名称")
|
||||||
|
private String classificationName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国标名称
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "国标名称")
|
||||||
|
private String gbName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "更新时间")
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建者
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "创建者")
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新者
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "更新者")
|
||||||
|
private String updateBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "备注")
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.ruoyi.system.mapper;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.ruoyi.core.mapper.BaseMapperPlus;
|
||||||
|
import org.ruoyi.system.domain.AssetClassification;
|
||||||
|
import org.ruoyi.system.domain.vo.AssetClassificationVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高等学校固定资产分类与代码Mapper接口
|
||||||
|
*
|
||||||
|
* @author cass
|
||||||
|
* @date 2025-09-24
|
||||||
|
*/
|
||||||
|
public interface AssetClassificationMapper extends BaseMapperPlus<AssetClassification, AssetClassificationVo> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据分类代码查询
|
||||||
|
*
|
||||||
|
* @param classificationCode 分类代码
|
||||||
|
* @return 高等学校固定资产分类与代码
|
||||||
|
*/
|
||||||
|
AssetClassification queryByClassificationCode(@Param("classificationCode") String classificationCode);
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package org.ruoyi.system.service;
|
||||||
|
|
||||||
|
import org.ruoyi.core.page.TableDataInfo;
|
||||||
|
import org.ruoyi.system.domain.AssetClassification;
|
||||||
|
import org.ruoyi.system.domain.bo.AssetClassificationBo;
|
||||||
|
import org.ruoyi.system.domain.vo.AssetClassificationVo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高等学校固定资产分类与代码Service接口
|
||||||
|
*
|
||||||
|
* @author cass
|
||||||
|
* @date 2025-09-24
|
||||||
|
*/
|
||||||
|
public interface IAssetClassificationService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询高等学校固定资产分类与代码
|
||||||
|
*/
|
||||||
|
AssetClassificationVo queryById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据分类代码查询
|
||||||
|
*/
|
||||||
|
AssetClassification queryByClassificationCode(String classificationCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询高等学校固定资产分类与代码列表
|
||||||
|
*/
|
||||||
|
TableDataInfo<AssetClassificationVo> queryPageList(AssetClassificationBo bo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询高等学校固定资产分类与代码列表
|
||||||
|
*/
|
||||||
|
List<AssetClassificationVo> queryList(AssetClassificationBo bo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增高等学校固定资产分类与代码
|
||||||
|
*/
|
||||||
|
Boolean insertByBo(AssetClassificationBo bo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改高等学校固定资产分类与代码
|
||||||
|
*/
|
||||||
|
Boolean updateByBo(AssetClassificationBo bo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验并批量删除高等学校固定资产分类与代码信息
|
||||||
|
*/
|
||||||
|
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入数据
|
||||||
|
*
|
||||||
|
* @param dataList 数据列表
|
||||||
|
* @param isUpdateSupport 是否更新支持
|
||||||
|
* @param operName 操作用户
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
String importData(List<AssetClassificationBo> dataList, Boolean isUpdateSupport, String operName);
|
||||||
|
}
|
||||||
@@ -1,261 +0,0 @@
|
|||||||
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<MinUsagePeriodImportVo> 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<MinUsagePeriod> 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<MinUsagePeriod> 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<MinUsagePeriodImportVo> 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<MinUsagePeriod> 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(" - 数据质量: 需要改进 (存在缺失字段)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
package org.ruoyi.system.service;
|
||||||
|
|
||||||
|
import com.alibaba.excel.EasyExcel;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新Excel文件分析测试
|
||||||
|
*
|
||||||
|
* @author cass
|
||||||
|
* @date 2025-09-24
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class NewExcelAnalysisTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新Excel文件路径
|
||||||
|
*/
|
||||||
|
private static final String NEW_EXCEL_FILE_PATH = "E:/z. WorkSpace/ruoyi-ai/workspace/高等学校固定资产分类与代码.xlsx";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分析新Excel文件结构
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void analyzeNewExcelFile() {
|
||||||
|
try {
|
||||||
|
log.info("=== 开始分析新Excel文件结构 ===");
|
||||||
|
|
||||||
|
File excelFile = new File(NEW_EXCEL_FILE_PATH);
|
||||||
|
if (!excelFile.exists()) {
|
||||||
|
log.error("Excel文件不存在: {}", NEW_EXCEL_FILE_PATH);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("文件信息:");
|
||||||
|
log.info("- 文件路径: {}", excelFile.getAbsolutePath());
|
||||||
|
log.info("- 文件大小: {} bytes", excelFile.length());
|
||||||
|
log.info("- 文件是否存在: {}", excelFile.exists());
|
||||||
|
log.info("- 文件是否可读: {}", excelFile.canRead());
|
||||||
|
|
||||||
|
// 1. 读取原始数据(不指定头部)
|
||||||
|
log.info("\n1. 读取原始数据(前20行)...");
|
||||||
|
try (InputStream inputStream = new FileInputStream(excelFile)) {
|
||||||
|
List<Map<Integer, String>> rawData = EasyExcel.read(inputStream)
|
||||||
|
.sheet()
|
||||||
|
.headRowNumber(0) // 不跳过头部
|
||||||
|
.doReadSync();
|
||||||
|
|
||||||
|
log.info(" 总共读取到 {} 行数据", rawData.size());
|
||||||
|
|
||||||
|
// 显示前20行数据
|
||||||
|
for (int i = 0; i < Math.min(20, rawData.size()); i++) {
|
||||||
|
Map<Integer, String> row = rawData.get(i);
|
||||||
|
log.info(" 第{}行: {}", i + 1, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 分析数据结构
|
||||||
|
log.info("\n2. 分析数据结构...");
|
||||||
|
analyzeDataStructure(excelFile);
|
||||||
|
|
||||||
|
// 3. 尝试按指定字段读取
|
||||||
|
log.info("\n3. 尝试按指定字段读取...");
|
||||||
|
tryReadWithFields(excelFile);
|
||||||
|
|
||||||
|
log.info("=== 新Excel文件结构分析完成 ===");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("分析新Excel文件失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分析数据结构
|
||||||
|
*/
|
||||||
|
private void analyzeDataStructure(File excelFile) throws Exception {
|
||||||
|
try (InputStream inputStream = new FileInputStream(excelFile)) {
|
||||||
|
List<Map<Integer, String>> rawData = EasyExcel.read(inputStream)
|
||||||
|
.sheet()
|
||||||
|
.headRowNumber(0)
|
||||||
|
.doReadSync();
|
||||||
|
|
||||||
|
log.info(" 数据行数: {}", rawData.size());
|
||||||
|
|
||||||
|
// 统计空行
|
||||||
|
int emptyRows = 0;
|
||||||
|
int headerRows = 0;
|
||||||
|
int categoryTitleRows = 0;
|
||||||
|
int dataRows = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < rawData.size(); i++) {
|
||||||
|
Map<Integer, String> row = rawData.get(i);
|
||||||
|
|
||||||
|
// 检查是否为空行
|
||||||
|
boolean isEmpty = row.values().stream().allMatch(value ->
|
||||||
|
value == null || value.trim().isEmpty());
|
||||||
|
|
||||||
|
if (isEmpty) {
|
||||||
|
emptyRows++;
|
||||||
|
} else {
|
||||||
|
// 检查是否是表头行
|
||||||
|
String firstCell = row.get(0);
|
||||||
|
if (firstCell != null && firstCell.contains("分类代码")) {
|
||||||
|
headerRows++;
|
||||||
|
} else if (firstCell != null && firstCell.trim().length() > 0 &&
|
||||||
|
(row.get(1) == null || row.get(1).trim().isEmpty())) {
|
||||||
|
// 只有第一列有值,其他列为空,可能是分类标题
|
||||||
|
categoryTitleRows++;
|
||||||
|
} else {
|
||||||
|
dataRows++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(" 空行数量: {}", emptyRows);
|
||||||
|
log.info(" 表头行数量: {}", headerRows);
|
||||||
|
log.info(" 分类标题行数量: {}", categoryTitleRows);
|
||||||
|
log.info(" 数据行数量: {}", dataRows);
|
||||||
|
|
||||||
|
// 显示一些分类标题行的例子
|
||||||
|
log.info(" 分类标题行示例:");
|
||||||
|
int categoryCount = 0;
|
||||||
|
for (int i = 0; i < rawData.size() && categoryCount < 5; i++) {
|
||||||
|
Map<Integer, String> row = rawData.get(i);
|
||||||
|
String firstCell = row.get(0);
|
||||||
|
if (firstCell != null && firstCell.trim().length() > 0 &&
|
||||||
|
(row.get(1) == null || row.get(1).trim().isEmpty())) {
|
||||||
|
log.info(" - 第{}行: {}", i + 1, firstCell);
|
||||||
|
categoryCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试按指定字段读取
|
||||||
|
*/
|
||||||
|
private void tryReadWithFields(File excelFile) throws Exception {
|
||||||
|
// 创建一个简单的VO类来测试字段映射
|
||||||
|
try (InputStream inputStream = new FileInputStream(excelFile)) {
|
||||||
|
List<Map<Integer, String>> rawData = EasyExcel.read(inputStream)
|
||||||
|
.sheet()
|
||||||
|
.headRowNumber(0)
|
||||||
|
.doReadSync();
|
||||||
|
|
||||||
|
log.info(" 尝试识别有效数据行...");
|
||||||
|
|
||||||
|
int validDataCount = 0;
|
||||||
|
for (int i = 0; i < rawData.size(); i++) {
|
||||||
|
Map<Integer, String> row = rawData.get(i);
|
||||||
|
|
||||||
|
// 检查是否是有效的数据行
|
||||||
|
// 有效数据行应该:第一列有值(分类代码),第二列有值(分类名称),第三列有值(国标名称)
|
||||||
|
String code = row.get(0);
|
||||||
|
String name = row.get(1);
|
||||||
|
String gbName = row.get(2);
|
||||||
|
|
||||||
|
if (code != null && !code.trim().isEmpty() &&
|
||||||
|
name != null && !name.trim().isEmpty() &&
|
||||||
|
gbName != null && !gbName.trim().isEmpty() &&
|
||||||
|
!code.contains("分类代码")) { // 排除表头行
|
||||||
|
|
||||||
|
validDataCount++;
|
||||||
|
if (validDataCount <= 10) {
|
||||||
|
log.info(" 有效数据第{}行: 代码={}, 名称={}, 国标名称={}",
|
||||||
|
validDataCount, code, name, gbName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(" 识别到 {} 条有效数据", validDataCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,303 @@
|
|||||||
|
package org.ruoyi.system.service;
|
||||||
|
|
||||||
|
import com.alibaba.excel.EasyExcel;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 简单的高等学校固定资产分类与代码导入测试
|
||||||
|
*
|
||||||
|
* @author cass
|
||||||
|
* @date 2025-09-24
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class SimpleAssetClassificationTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新Excel文件路径
|
||||||
|
*/
|
||||||
|
private static final String NEW_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 testAssetClassificationImportToDatabase() {
|
||||||
|
try {
|
||||||
|
log.info("=== 开始高等学校固定资产分类与代码导入测试 ===");
|
||||||
|
|
||||||
|
// 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<Map<Integer, String>> dataList = readExcelFile();
|
||||||
|
log.info(" 读取到 {} 条原始数据", dataList.size());
|
||||||
|
|
||||||
|
// 5. 数据清洗
|
||||||
|
log.info("5. 数据清洗...");
|
||||||
|
List<Map<Integer, String>> cleanedData = cleanData(dataList);
|
||||||
|
log.info(" 清洗后有效数据: {} 条", cleanedData.size());
|
||||||
|
|
||||||
|
// 6. 批量插入数据库
|
||||||
|
log.info("6. 批量插入数据库...");
|
||||||
|
int successCount = insertDataToDatabase(connection, cleanedData);
|
||||||
|
log.info(" 插入完成: 成功 {} 条", successCount);
|
||||||
|
|
||||||
|
// 7. 验证数据库中的数据
|
||||||
|
log.info("7. 验证数据库中的数据...");
|
||||||
|
int dbCount = getDatabaseRecordCount(connection);
|
||||||
|
log.info(" 数据库中共有 {} 条记录", dbCount);
|
||||||
|
|
||||||
|
// 8. 显示部分数据
|
||||||
|
log.info("8. 显示部分数据...");
|
||||||
|
showSampleData(connection);
|
||||||
|
|
||||||
|
// 9. 数据质量分析
|
||||||
|
log.info("9. 数据质量分析...");
|
||||||
|
analyzeDataQuality(connection);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("=== 高等学校固定资产分类与代码导入测试完成 ===");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("高等学校固定资产分类与代码导入测试失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建表(如果不存在)
|
||||||
|
*/
|
||||||
|
private void createTableIfNotExists(Connection connection) throws Exception {
|
||||||
|
String createTableSql = """
|
||||||
|
CREATE TABLE IF NOT EXISTS `asset_classification` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`classification_code` varchar(20) NOT NULL COMMENT '分类代码',
|
||||||
|
`classification_name` varchar(200) NOT NULL COMMENT '分类名称',
|
||||||
|
`gb_name` varchar(200) 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_classification_code` (`classification_code`),
|
||||||
|
KEY `idx_classification_name` (`classification_name`),
|
||||||
|
KEY `idx_gb_name` (`gb_name`)
|
||||||
|
) 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 asset_classification";
|
||||||
|
try (Statement statement = connection.createStatement()) {
|
||||||
|
statement.executeUpdate(deleteSql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取Excel文件
|
||||||
|
*/
|
||||||
|
private List<Map<Integer, String>> readExcelFile() throws Exception {
|
||||||
|
File excelFile = new File(NEW_EXCEL_FILE_PATH);
|
||||||
|
if (!excelFile.exists()) {
|
||||||
|
throw new RuntimeException("Excel文件不存在: " + NEW_EXCEL_FILE_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStream inputStream = new FileInputStream(excelFile)) {
|
||||||
|
return EasyExcel.read(inputStream)
|
||||||
|
.sheet()
|
||||||
|
.doReadSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据清洗
|
||||||
|
*/
|
||||||
|
private List<Map<Integer, String>> cleanData(List<Map<Integer, String>> dataList) {
|
||||||
|
return dataList.stream()
|
||||||
|
.filter(this::isValidData)
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证数据是否有效
|
||||||
|
*/
|
||||||
|
private boolean isValidData(Map<Integer, String> data) {
|
||||||
|
// 过滤空行
|
||||||
|
if (data == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String code = data.get(0);
|
||||||
|
String name = data.get(1);
|
||||||
|
String gbName = data.get(2);
|
||||||
|
|
||||||
|
// 过滤表头行
|
||||||
|
if ("分类代码".equals(code) ||
|
||||||
|
"分类名称".equals(name) ||
|
||||||
|
"国标名称".equals(gbName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤分类标题行(只有第一列有值,其他列为空)
|
||||||
|
if (code != null && !code.trim().isEmpty() &&
|
||||||
|
(name == null || name.trim().isEmpty()) &&
|
||||||
|
(gbName == null || gbName.trim().isEmpty())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤包含"表"、"续表"等标题行
|
||||||
|
if (code != null &&
|
||||||
|
(code.contains("表") ||
|
||||||
|
code.contains("续表"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证必填字段
|
||||||
|
return code != null && !code.trim().isEmpty() &&
|
||||||
|
name != null && !name.trim().isEmpty() &&
|
||||||
|
gbName != null && !gbName.trim().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入数据到数据库
|
||||||
|
*/
|
||||||
|
private int insertDataToDatabase(Connection connection, List<Map<Integer, String>> dataList) throws Exception {
|
||||||
|
String insertSql = "INSERT INTO asset_classification (classification_code, classification_name, gb_name) VALUES (?, ?, ?)";
|
||||||
|
|
||||||
|
int successCount = 0;
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(insertSql)) {
|
||||||
|
for (Map<Integer, String> data : dataList) {
|
||||||
|
try {
|
||||||
|
String code = data.get(0);
|
||||||
|
String name = data.get(1);
|
||||||
|
String gbName = data.get(2);
|
||||||
|
|
||||||
|
statement.setString(1, code);
|
||||||
|
statement.setString(2, name);
|
||||||
|
statement.setString(3, gbName);
|
||||||
|
|
||||||
|
statement.executeUpdate();
|
||||||
|
successCount++;
|
||||||
|
|
||||||
|
if (successCount <= 5) {
|
||||||
|
log.info(" 插入成功: {} - {}", code, name);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(" 插入失败: {} - {}", data.get(0), data.get(1), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return successCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数据库记录数
|
||||||
|
*/
|
||||||
|
private int getDatabaseRecordCount(Connection connection) throws Exception {
|
||||||
|
String countSql = "SELECT COUNT(*) FROM asset_classification";
|
||||||
|
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 asset_classification LIMIT 10";
|
||||||
|
try (Statement statement = connection.createStatement()) {
|
||||||
|
var resultSet = statement.executeQuery(selectSql);
|
||||||
|
int count = 0;
|
||||||
|
while (resultSet.next() && count < 10) {
|
||||||
|
count++;
|
||||||
|
String code = resultSet.getString("classification_code");
|
||||||
|
String name = resultSet.getString("classification_name");
|
||||||
|
String gbName = resultSet.getString("gb_name");
|
||||||
|
|
||||||
|
log.info(" 第{}条: 代码={}, 名称={}, 国标名称={}",
|
||||||
|
count, code, name, gbName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据质量分析
|
||||||
|
*/
|
||||||
|
private void analyzeDataQuality(Connection connection) throws Exception {
|
||||||
|
log.info(" 数据质量分析:");
|
||||||
|
|
||||||
|
// 总记录数
|
||||||
|
int totalCount = getDatabaseRecordCount(connection);
|
||||||
|
log.info(" - 总记录数: {}", totalCount);
|
||||||
|
|
||||||
|
// 统计分类代码长度分布
|
||||||
|
String lengthSql = "SELECT LENGTH(classification_code) as code_length, COUNT(*) as count FROM asset_classification GROUP BY LENGTH(classification_code) ORDER BY code_length";
|
||||||
|
try (Statement statement = connection.createStatement()) {
|
||||||
|
var resultSet = statement.executeQuery(lengthSql);
|
||||||
|
log.info(" - 分类代码长度分布:");
|
||||||
|
while (resultSet.next()) {
|
||||||
|
int length = resultSet.getInt("code_length");
|
||||||
|
int count = resultSet.getInt("count");
|
||||||
|
log.info(" * {}位: {} 条", length, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计国标名称分布
|
||||||
|
String gbNameSql = "SELECT gb_name, COUNT(*) as count FROM asset_classification GROUP BY gb_name ORDER BY count DESC LIMIT 10";
|
||||||
|
try (Statement statement = connection.createStatement()) {
|
||||||
|
var resultSet = statement.executeQuery(gbNameSql);
|
||||||
|
log.info(" - 国标名称分布(前10):");
|
||||||
|
while (resultSet.next()) {
|
||||||
|
String gbName = resultSet.getString("gb_name");
|
||||||
|
int count = resultSet.getInt("count");
|
||||||
|
log.info(" * {}: {} 条", gbName, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(" - 数据质量: 优秀 (所有字段都完整)");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# 测试环境配置
|
||||||
|
spring:
|
||||||
|
datasource:
|
||||||
|
type: com.zaxxer.hikari.HikariDataSource
|
||||||
|
dynamic:
|
||||||
|
p6spy: false
|
||||||
|
primary: master
|
||||||
|
strict: true
|
||||||
|
datasource:
|
||||||
|
master:
|
||||||
|
type: ${spring.datasource.type}
|
||||||
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
|
url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||||
|
username: root
|
||||||
|
password: 666666
|
||||||
|
hikari:
|
||||||
|
maxPoolSize: 10
|
||||||
|
minIdle: 5
|
||||||
|
connectionTimeout: 30000
|
||||||
|
validationTimeout: 5000
|
||||||
|
idleTimeout: 600000
|
||||||
|
maxLifetime: 1800000
|
||||||
|
connectionTestQuery: SELECT 1
|
||||||
|
keepaliveTime: 30000
|
||||||
|
|
||||||
|
# Redis配置(测试环境可以禁用)
|
||||||
|
data:
|
||||||
|
redis:
|
||||||
|
host: 127.0.0.1
|
||||||
|
port: 6379
|
||||||
|
database: 0
|
||||||
|
timeout: 10S
|
||||||
|
|
||||||
|
# MyBatis Plus配置
|
||||||
|
mybatis-plus:
|
||||||
|
mapper-locations: classpath*:mapper/**/*Mapper.xml
|
||||||
|
type-aliases-package: org.ruoyi.**.domain
|
||||||
|
configuration:
|
||||||
|
map-underscore-to-camel-case: true
|
||||||
|
cache-enabled: false
|
||||||
|
call-setters-on-nulls: true
|
||||||
|
jdbc-type-for-null: 'null'
|
||||||
|
global-config:
|
||||||
|
db-config:
|
||||||
|
id-type: AUTO
|
||||||
|
logic-delete-field: delFlag
|
||||||
|
logic-delete-value: 2
|
||||||
|
logic-not-delete-value: 0
|
||||||
|
|
||||||
|
# 日志配置
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
org.ruoyi: DEBUG
|
||||||
|
org.springframework: WARN
|
||||||
|
com.baomidou.mybatisplus: WARN
|
||||||
|
pattern:
|
||||||
|
console: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n'
|
||||||
16
script/sql/asset_classification.sql
Normal file
16
script/sql/asset_classification.sql
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
-- 高等学校固定资产分类与代码表
|
||||||
|
CREATE TABLE `asset_classification` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`classification_code` varchar(20) NOT NULL COMMENT '分类代码',
|
||||||
|
`classification_name` varchar(200) NOT NULL COMMENT '分类名称',
|
||||||
|
`gb_name` varchar(200) 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_classification_code` (`classification_code`),
|
||||||
|
KEY `idx_classification_name` (`classification_name`),
|
||||||
|
KEY `idx_gb_name` (`gb_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='高等学校固定资产分类与代码表';
|
||||||
BIN
workspace/报废审核test.xlsx
Normal file
BIN
workspace/报废审核test.xlsx
Normal file
Binary file not shown.
Reference in New Issue
Block a user