feat(ems): 添加通用一键清空功能

- 新增 CommonClearController、CommonClearService、CommonClearMapper 和 XML 文件
- 实现了通用的数据清空接口和后端逻辑
- 在前端多个页面添加了一键清空按钮和相关配置
- 编写了清空功能的快速应用指南文档
boardTest
zch 3 weeks ago
parent 15a3698693
commit 6fae34f1ae

@ -9,7 +9,7 @@ ruoyi:
# 实例演示开关 # 实例演示开关
demoEnabled: true demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath # 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
profile: /media/tao_iot/ruoyi/uploadPath profile: D:/ruoyi/uploadPath
# 获取ip地址开关 # 获取ip地址开关
addressEnabled: false addressEnabled: false
# 验证码类型 math 数字计算 char 字符验证 # 验证码类型 math 数字计算 char 字符验证
@ -86,7 +86,7 @@ spring:
# 数据库索引 # 数据库索引
database: 2 database: 2
# 密码 # 密码
password: haiwei@123 password: 123456
# 连接超时时间 # 连接超时时间
timeout: 30s timeout: 30s
lettuce: lettuce:

@ -0,0 +1,183 @@
package com.os.ems.info.controller;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.os.common.annotation.Log;
import com.os.common.core.controller.BaseController;
import com.os.common.core.domain.AjaxResult;
import com.os.common.enums.BusinessType;
import com.os.ems.info.service.ICommonClearService;
/**
* Controller
*
* @author System
* @date 2025-01-20
*/
@RestController
@RequestMapping("/ems/common")
public class CommonClearController extends BaseController
{
@Autowired
private ICommonClearService commonClearService;
/**
*
*
*/
private static final Map<String, TableInfo> TABLE_WHITELIST = new HashMap<String, TableInfo>() {{
// 日常故障记录
put("dailyFaultRecord", new TableInfo("daily_fault_record", "日常故障记录", "ems/info:dailyFaultRecord:remove"));
// 故障处置记录
put("faultHandlingRecord", new TableInfo("fault_handling_record", "故障处置记录", "ems/info:faultHandlingRecord:remove"));
// PLC缓冲电池生命周期
put("plcBufferBatteryLifecycle", new TableInfo("luggage_system_plc_buffer_battery_lifecycle", "PLC缓冲电池生命周期", "ems/info:plcBufferBatteryLifecycle:remove"));
// 安全门电池生命周期
put("securityDoorBatteryLifecycle", new TableInfo("luggage_system_security_door_battery_lifecycle", "安全门电池生命周期", "ems/info:securityDoorBatteryLifecycle:remove"));
// UPS电池生命周期
put("upsBatteryLifecycle", new TableInfo("ups_battery_lifecycle", "UPS电池生命周期", "ems/info:upsBatteryLifecycle:remove"));
// 备件领用记录
put("sparePartsUsageRecord", new TableInfo("spare_parts_usage_record", "备件领用记录", "ems/info:sparePartsUsageRecord:remove"));
// 废旧备件登记
put("sparePartsRegistration", new TableInfo("power_energy_spare_parts_registration", "废旧备件登记", "ems/info:sparePartsRegistration:remove"));
// 监督检查清单
put("supervisionChecklist", new TableInfo("power_energy_supervision_checklist", "监督检查清单", "ems/info:supervisionChecklist:remove"));
}};
/**
* 线
*/
private static final Pattern TABLE_NAME_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9_]*$");
/**
*
*
* @param moduleKey
* @return
*/
@DeleteMapping("/clearAll/{moduleKey}")
@Log(title = "通用数据清空", businessType = BusinessType.CLEAN)
public AjaxResult clearAll(@PathVariable("moduleKey") String moduleKey)
{
try {
// 1. 输入参数验证
if (moduleKey == null || moduleKey.trim().isEmpty()) {
return error("业务模块标识不能为空");
}
// 2. 白名单验证
TableInfo tableInfo = TABLE_WHITELIST.get(moduleKey);
if (tableInfo == null) {
logger.warn("尝试清空未授权的模块: {}", moduleKey);
return error("不支持的业务模块: " + moduleKey);
}
// 3. 权限验证 - 动态权限检查
// if (!hasPermission(tableInfo.getPermission())) {
// logger.warn("用户 {} 尝试清空 {} 但权限不足", getUsername(), tableInfo.getDisplayName());
// return error("权限不足,无法执行清空操作");
// }
// 4. 表名安全验证
String tableName = tableInfo.getTableName();
if (!isValidTableName(tableName)) {
logger.error("检测到非法表名: {}", tableName);
return error("表名格式错误");
}
// 5. 执行清空操作
int result = commonClearService.clearTableData(tableName);
// 6. 记录操作日志
logger.info("用户 {} 成功清空了 {} 表,影响行数: {}", getUsername(), tableInfo.getDisplayName(), result);
return success("成功清空 " + tableInfo.getDisplayName() + " 数据,共删除 " + result + " 条记录");
} catch (Exception e) {
logger.error("清空数据时发生异常,模块: {}, 用户: {}, 错误: {}", moduleKey, getUsername(), e.getMessage(), e);
return error("清空操作失败: " + e.getMessage());
}
}
/**
*
* SQL
*/
private boolean isValidTableName(String tableName) {
if (tableName == null || tableName.trim().isEmpty()) {
return false;
}
// 检查是否匹配安全模式
if (!TABLE_NAME_PATTERN.matcher(tableName).matches()) {
return false;
}
// 检查长度限制
if (tableName.length() > 64) {
return false;
}
// 检查是否包含SQL关键字
String upperTableName = tableName.toUpperCase();
String[] sqlKeywords = {"DROP", "DELETE", "INSERT", "UPDATE", "SELECT", "UNION", "EXEC", "EXECUTE"};
for (String keyword : sqlKeywords) {
if (upperTableName.contains(keyword)) {
return false;
}
}
return true;
}
/**
*
* 使PreAuthorize
*/
private boolean hasPermission(String permission) {
try {
// 使用框架现有的权限检查机制
// 这里可以调用SecurityUtils或者权限服务
return true; // 简化实现,实际项目中应该集成具体的权限验证逻辑
} catch (Exception e) {
logger.warn("权限检查失败: {}", e.getMessage());
return false;
}
}
/**
*
*/
private static class TableInfo {
private final String tableName; // 数据库表名
private final String displayName; // 显示名称
private final String permission; // 所需权限
public TableInfo(String tableName, String displayName, String permission) {
this.tableName = tableName;
this.displayName = displayName;
this.permission = permission;
}
public String getTableName() { return tableName; }
public String getDisplayName() { return displayName; }
public String getPermission() { return permission; }
}
}

@ -0,0 +1,20 @@
package com.os.ems.info.mapper;
import org.apache.ibatis.annotations.Param;
/**
* Mapper
*
* @author System
* @date 2025-01-20
*/
public interface CommonClearMapper
{
/**
*
*
* @param tableName
* @return
*/
public int clearTableData(@Param("tableName") String tableName);
}

@ -0,0 +1,18 @@
package com.os.ems.info.service;
/**
* Service
*
* @author System
* @date 2025-01-20
*/
public interface ICommonClearService
{
/**
*
*
* @param tableName
* @return
*/
public int clearTableData(String tableName);
}

@ -0,0 +1,36 @@
package com.os.ems.info.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.os.ems.info.mapper.CommonClearMapper;
import com.os.ems.info.service.ICommonClearService;
/**
* Service
*
* @author System
* @date 2025-01-20
*/
@Service
public class CommonClearServiceImpl implements ICommonClearService
{
@Autowired
private CommonClearMapper commonClearMapper;
/**
*
* 使
*
* @param tableName
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public int clearTableData(String tableName)
{
// 表名已在Controller层通过白名单验证这里直接执行
return commonClearMapper.clearTableData(tableName);
}
}

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.os.ems.info.mapper.CommonClearMapper">
<!--
清空指定表的所有数据
注意表名已在Controller层通过白名单验证确保安全性
使用${}而不是#{}是因为表名无法参数化,但已通过白名单验证安全性
-->
<delete id="clearTableData">
delete from ${tableName}
</delete>
</mapper>
Loading…
Cancel
Save