1、新增降噪日志数据健康监测告警
2、IP联动封禁功能完善
This commit is contained in:
@@ -197,7 +197,12 @@
|
||||
<artifactId>DmJdbcDriver18</artifactId>
|
||||
<version>8.1.2.141</version> <!-- 请根据你的数据库版本替换 -->
|
||||
</dependency>
|
||||
|
||||
<!-- Bouncy Castle 国密算法支持 -->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15to18</artifactId>
|
||||
<version>1.78</version> <!-- 兼容 Java 1.8 -->
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.common.entity;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* 联动设备表实体类(防火墙设备信息)
|
||||
* 对应表: device_interlocking
|
||||
*/
|
||||
public class DeviceInterlocking {
|
||||
private Long id;
|
||||
private String deviceName; // 联动安全设备名称(防火墙)
|
||||
private String vendor; // 厂商
|
||||
private String deptId; // 所属组织机构(部门ID)
|
||||
private Integer banLimit; // 封禁上限
|
||||
private String ip; // IP地址
|
||||
private String apiUrl; // API地址
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private OffsetDateTime createTime;
|
||||
private Long updateBy;
|
||||
private OffsetDateTime updateTime;
|
||||
private String remark;
|
||||
private String authUsername; // 用户名
|
||||
private String authPassword; // 密码
|
||||
|
||||
// Getter and Setter
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
public String getDeviceName() { return deviceName; }
|
||||
public void setDeviceName(String deviceName) { this.deviceName = deviceName; }
|
||||
|
||||
public String getVendor() { return vendor; }
|
||||
public void setVendor(String vendor) { this.vendor = vendor; }
|
||||
|
||||
public String getDeptId() { return deptId; }
|
||||
public void setDeptId(String deptId) { this.deptId = deptId; }
|
||||
|
||||
public Integer getBanLimit() { return banLimit; }
|
||||
public void setBanLimit(Integer banLimit) { this.banLimit = banLimit; }
|
||||
|
||||
public String getIp() { return ip; }
|
||||
public void setIp(String ip) { this.ip = ip; }
|
||||
|
||||
public String getApiUrl() { return apiUrl; }
|
||||
public void setApiUrl(String apiUrl) { this.apiUrl = apiUrl; }
|
||||
|
||||
public String getTenantId() { return tenantId; }
|
||||
public void setTenantId(String tenantId) { this.tenantId = tenantId; }
|
||||
|
||||
public Long getCreateDept() { return createDept; }
|
||||
public void setCreateDept(Long createDept) { this.createDept = createDept; }
|
||||
|
||||
public Long getCreateBy() { return createBy; }
|
||||
public void setCreateBy(Long createBy) { this.createBy = createBy; }
|
||||
|
||||
public OffsetDateTime getCreateTime() { return createTime; }
|
||||
public void setCreateTime(OffsetDateTime createTime) { this.createTime = createTime; }
|
||||
|
||||
public Long getUpdateBy() { return updateBy; }
|
||||
public void setUpdateBy(Long updateBy) { this.updateBy = updateBy; }
|
||||
|
||||
public OffsetDateTime getUpdateTime() { return updateTime; }
|
||||
public void setUpdateTime(OffsetDateTime updateTime) { this.updateTime = updateTime; }
|
||||
|
||||
public String getRemark() { return remark; }
|
||||
public void setRemark(String remark) { this.remark = remark; }
|
||||
|
||||
public String getAuthUsername() { return authUsername; }
|
||||
public void setAuthUsername(String authUsername) { this.authUsername = authUsername; }
|
||||
|
||||
public String getAuthPassword() { return authPassword; }
|
||||
public void setAuthPassword(String authPassword) { this.authPassword = authPassword; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DeviceInterlocking{" +
|
||||
"id=" + id +
|
||||
", deviceName='" + deviceName + '\'' +
|
||||
", vendor='" + vendor + '\'' +
|
||||
", ip='" + ip + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
package com.common.entity;
|
||||
|
||||
import com.Modules.etl.handler.ArrayIntegerTypeHandler;
|
||||
import com.Modules.etl.handler.ArrayStringTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.apache.ibatis.type.TypeHandler;
|
||||
import org.apache.ibatis.type.ArrayTypeHandler;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 封禁指令表实体类
|
||||
* 对应表: device_interlocking_cmd
|
||||
*/
|
||||
public class DeviceInterlockingCmd {
|
||||
private Long id;
|
||||
private Long probeId; // 探针ID
|
||||
private String probeIp; // 探针IP
|
||||
private Integer[] deviceInterlockingId; // 联动设备ID(数组)
|
||||
private String[] deviceInterlockingIp; // 联动设备IP(数组)
|
||||
private String[] banIps; // 封禁IP(数组)
|
||||
private String banMethod; // 封禁方式(0:手工、1:自动)
|
||||
private String banType; // 封禁类型(1:白名单、0:黑名单)
|
||||
private String cmdStatus; // 指令状态(0:未执行、1:已完成、2:执行中)
|
||||
private Integer banDuration; // 封禁时长(秒,-1表示永久)
|
||||
private OffsetDateTime createTime;
|
||||
private OffsetDateTime updateTime;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Long updateBy;
|
||||
private String remark;
|
||||
private Integer banOperationType; // 封禁操作类型(0:新增、1:删除)
|
||||
|
||||
// Getter and Setter
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
public Long getProbeId() { return probeId; }
|
||||
public void setProbeId(Long probeId) { this.probeId = probeId; }
|
||||
|
||||
public String getProbeIp() { return probeIp; }
|
||||
public void setProbeIp(String probeIp) { this.probeIp = probeIp; }
|
||||
|
||||
public Integer[] getDeviceInterlockingId() { return deviceInterlockingId; }
|
||||
public void setDeviceInterlockingId(Integer[] deviceInterlockingId) { this.deviceInterlockingId = deviceInterlockingId; }
|
||||
|
||||
public String[] getDeviceInterlockingIp() { return deviceInterlockingIp; }
|
||||
public void setDeviceInterlockingIp(String[] deviceInterlockingIp) { this.deviceInterlockingIp = deviceInterlockingIp; }
|
||||
|
||||
public String[] getBanIps() { return banIps; }
|
||||
public void setBanIps(String[] banIps) { this.banIps = banIps; }
|
||||
|
||||
public String getBanMethod() { return banMethod; }
|
||||
public void setBanMethod(String banMethod) { this.banMethod = banMethod; }
|
||||
|
||||
public String getBanType() { return banType; }
|
||||
public void setBanType(String banType) { this.banType = banType; }
|
||||
|
||||
public String getCmdStatus() { return cmdStatus; }
|
||||
public void setCmdStatus(String cmdStatus) { this.cmdStatus = cmdStatus; }
|
||||
|
||||
public Integer getBanDuration() { return banDuration; }
|
||||
public void setBanDuration(Integer banDuration) { this.banDuration = banDuration; }
|
||||
|
||||
public OffsetDateTime getCreateTime() { return createTime; }
|
||||
public void setCreateTime(OffsetDateTime createTime) { this.createTime = createTime; }
|
||||
|
||||
public OffsetDateTime getUpdateTime() { return updateTime; }
|
||||
public void setUpdateTime(OffsetDateTime updateTime) { this.updateTime = updateTime; }
|
||||
|
||||
public String getTenantId() { return tenantId; }
|
||||
public void setTenantId(String tenantId) { this.tenantId = tenantId; }
|
||||
|
||||
public Long getCreateDept() { return createDept; }
|
||||
public void setCreateDept(Long createDept) { this.createDept = createDept; }
|
||||
|
||||
public Long getCreateBy() { return createBy; }
|
||||
public void setCreateBy(Long createBy) { this.createBy = createBy; }
|
||||
|
||||
public Long getUpdateBy() { return updateBy; }
|
||||
public void setUpdateBy(Long updateBy) { this.updateBy = updateBy; }
|
||||
|
||||
public String getRemark() { return remark; }
|
||||
public void setRemark(String remark) { this.remark = remark; }
|
||||
|
||||
public Integer getBanOperationType() { return banOperationType; }
|
||||
public void setBanOperationType(Integer banOperationType) { this.banOperationType = banOperationType; }
|
||||
|
||||
// ========== 便利方法:数组与List互转 ==========
|
||||
|
||||
/**
|
||||
* 获取设备联动ID列表
|
||||
*/
|
||||
public List<Integer> getDeviceInterlockingIdList() {
|
||||
return deviceInterlockingId != null ? Arrays.asList(deviceInterlockingId) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置设备联动ID列表
|
||||
*/
|
||||
public void setDeviceInterlockingIdList(List<Integer> list) {
|
||||
this.deviceInterlockingId = list != null ? list.toArray(new Integer[0]) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备联动IP列表
|
||||
*/
|
||||
public List<String> getDeviceInterlockingIpList() {
|
||||
return deviceInterlockingIp != null ? Arrays.asList(deviceInterlockingIp) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置设备联动IP列表
|
||||
*/
|
||||
public void setDeviceInterlockingIpList(List<String> list) {
|
||||
this.deviceInterlockingIp = list != null ? list.toArray(new String[0]) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取封禁IP列表
|
||||
*/
|
||||
public List<String> getBanIpsList() {
|
||||
return banIps != null ? Arrays.asList(banIps) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置封禁IP列表
|
||||
*/
|
||||
public void setBanIpsList(List<String> list) {
|
||||
this.banIps = list != null ? list.toArray(new String[0]) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DeviceInterlockingCmd{" +
|
||||
"id=" + id +
|
||||
", probeId=" + probeId +
|
||||
", probeIp='" + probeIp + '\'' +
|
||||
", banType='" + banType + '\'' +
|
||||
", cmdStatus='" + cmdStatus + '\'' +
|
||||
", banOperationType=" + banOperationType +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package com.common.entity;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* 封禁记录表实体类
|
||||
* 对应表: device_interlocking_log
|
||||
*/
|
||||
public class DeviceInterlockingLog {
|
||||
private Long id;
|
||||
private Long deviceInterlockingCmdId; // 封禁指令ID
|
||||
private Long deviceInterlockingId; // 封禁设备ID
|
||||
private String banIp; // 封禁IP地址
|
||||
private String deviceName; // 封禁设备名称
|
||||
private OffsetDateTime banTime; // 封禁时间
|
||||
private String banMethod; // 封禁方式(0.人工、1.自动化封禁)
|
||||
private Integer banResult; // 联动结果(成功:1、失败:0)
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private OffsetDateTime createTime;
|
||||
private Long updateBy;
|
||||
private OffsetDateTime updateTime;
|
||||
private String remark;
|
||||
private String respBody; // 响应body
|
||||
private String reqBody; // 请求body
|
||||
|
||||
// Getter and Setter
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
public Long getDeviceInterlockingCmdId() { return deviceInterlockingCmdId; }
|
||||
public void setDeviceInterlockingCmdId(Long deviceInterlockingCmdId) { this.deviceInterlockingCmdId = deviceInterlockingCmdId; }
|
||||
|
||||
public Long getDeviceInterlockingId() { return deviceInterlockingId; }
|
||||
public void setDeviceInterlockingId(Long deviceInterlockingId) { this.deviceInterlockingId = deviceInterlockingId; }
|
||||
|
||||
public String getBanIp() { return banIp; }
|
||||
public void setBanIp(String banIp) { this.banIp = banIp; }
|
||||
|
||||
public String getDeviceName() { return deviceName; }
|
||||
public void setDeviceName(String deviceName) { this.deviceName = deviceName; }
|
||||
|
||||
public OffsetDateTime getBanTime() { return banTime; }
|
||||
public void setBanTime(OffsetDateTime banTime) { this.banTime = banTime; }
|
||||
|
||||
public String getBanMethod() { return banMethod; }
|
||||
public void setBanMethod(String banMethod) { this.banMethod = banMethod; }
|
||||
|
||||
public Integer getBanResult() { return banResult; }
|
||||
public void setBanResult(Integer banResult) { this.banResult = banResult; }
|
||||
|
||||
public String getTenantId() { return tenantId; }
|
||||
public void setTenantId(String tenantId) { this.tenantId = tenantId; }
|
||||
|
||||
public Long getCreateDept() { return createDept; }
|
||||
public void setCreateDept(Long createDept) { this.createDept = createDept; }
|
||||
|
||||
public Long getCreateBy() { return createBy; }
|
||||
public void setCreateBy(Long createBy) { this.createBy = createBy; }
|
||||
|
||||
public OffsetDateTime getCreateTime() { return createTime; }
|
||||
public void setCreateTime(OffsetDateTime createTime) { this.createTime = createTime; }
|
||||
|
||||
public Long getUpdateBy() { return updateBy; }
|
||||
public void setUpdateBy(Long updateBy) { this.updateBy = updateBy; }
|
||||
|
||||
public OffsetDateTime getUpdateTime() { return updateTime; }
|
||||
public void setUpdateTime(OffsetDateTime updateTime) { this.updateTime = updateTime; }
|
||||
|
||||
public String getRemark() { return remark; }
|
||||
public void setRemark(String remark) { this.remark = remark; }
|
||||
|
||||
public String getRespBody() { return respBody; }
|
||||
public void setRespBody(String respBody) { this.respBody = respBody; }
|
||||
|
||||
public String getReqBody() { return reqBody; }
|
||||
public void setReqBody(String reqBody) { this.reqBody = reqBody; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DeviceInterlockingLog{" +
|
||||
"id=" + id +
|
||||
", deviceInterlockingCmdId=" + deviceInterlockingCmdId +
|
||||
", banIp='" + banIp + '\'' +
|
||||
", deviceName='" + deviceName + '\'' +
|
||||
", banResult=" + banResult +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package com.common.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 微信通知实体类
|
||||
* 对应表: wecom_notification
|
||||
*/
|
||||
@Data
|
||||
public class WecomNotification {
|
||||
|
||||
/** 企微通知id */
|
||||
private Long wecomNotificationId;
|
||||
|
||||
/** 用户信息 */
|
||||
private String userId;
|
||||
|
||||
/** 通知名称 */
|
||||
private String wecomNotificationName;
|
||||
|
||||
/** 通知IP */
|
||||
private String wecomNotificationIp;
|
||||
|
||||
/** 通知类型 */
|
||||
private String wecomNotificationType;
|
||||
|
||||
/** 通知等级 */
|
||||
private String wecomNotificationLevel;
|
||||
|
||||
/** 通知内容 */
|
||||
private String wecomNotificationContent;
|
||||
|
||||
/** 告警通知时间 */
|
||||
private LocalDateTime wecomNotificationTime;
|
||||
|
||||
/** 租户编号 */
|
||||
private String tenantId;
|
||||
|
||||
/** 创建部门 */
|
||||
private Long createDept;
|
||||
|
||||
/** 创建者 */
|
||||
private Long createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/** 更新者 */
|
||||
private Long updateBy;
|
||||
|
||||
/** 更新时间 */
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
|
||||
/** 通知状态(0:已发送, 1:未发送) */
|
||||
private String wecomNotificationStatus;
|
||||
|
||||
public WecomNotification() {
|
||||
}
|
||||
|
||||
public WecomNotification(String wecomNotificationName, String wecomNotificationType,
|
||||
String wecomNotificationLevel, String wecomNotificationContent) {
|
||||
this.wecomNotificationName = wecomNotificationName;
|
||||
this.wecomNotificationType = wecomNotificationType;
|
||||
this.wecomNotificationLevel = wecomNotificationLevel;
|
||||
this.wecomNotificationContent = wecomNotificationContent;
|
||||
this.wecomNotificationTime = LocalDateTime.now();
|
||||
this.wecomNotificationStatus = "1"; // 默认未发送
|
||||
this.createTime = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package com.common.mapper;
|
||||
|
||||
import com.Modules.etl.handler.ArrayIntegerTypeHandler;
|
||||
import com.Modules.etl.handler.ArrayStringTypeHandler;
|
||||
import com.common.entity.DeviceInterlockingCmd;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface DeviceInterlockingCmdMapper {
|
||||
|
||||
/**
|
||||
* 根据ID查询
|
||||
*/
|
||||
@Select("SELECT * FROM device_interlocking_cmd WHERE id = #{id}")
|
||||
@Results({
|
||||
@Result(column = "device_interlocking_id", property = "deviceInterlockingId",
|
||||
typeHandler = ArrayIntegerTypeHandler.class),
|
||||
@Result(column = "device_interlocking_ip", property = "deviceInterlockingIp",
|
||||
typeHandler = ArrayStringTypeHandler.class),
|
||||
@Result(column = "ban_ips", property = "banIps",
|
||||
typeHandler = ArrayStringTypeHandler.class)
|
||||
})
|
||||
DeviceInterlockingCmd selectById(Long id);
|
||||
|
||||
/**
|
||||
* 查询待执行的指令
|
||||
* @param probeId 探针ID
|
||||
* @return 待执行指令列表
|
||||
*/
|
||||
@Select("SELECT * FROM device_interlocking_cmd WHERE probe_id = #{probeId} AND cmd_status = '0' ORDER BY create_time ASC")
|
||||
@Results({
|
||||
@Result(column = "device_interlocking_id", property = "deviceInterlockingId",
|
||||
typeHandler = ArrayIntegerTypeHandler.class),
|
||||
@Result(column = "device_interlocking_ip", property = "deviceInterlockingIp",
|
||||
typeHandler = ArrayStringTypeHandler.class),
|
||||
@Result(column = "ban_ips", property = "banIps",
|
||||
typeHandler = ArrayStringTypeHandler.class)
|
||||
})
|
||||
List<DeviceInterlockingCmd> selectPendingCommands(@Param("probeId") Long probeId);
|
||||
|
||||
/**
|
||||
* 根据探针ID和状态查询
|
||||
*/
|
||||
@Select("SELECT * FROM device_interlocking_cmd WHERE probe_id = #{probeId} AND cmd_status = #{cmdStatus}")
|
||||
@Results({
|
||||
@Result(column = "device_interlocking_id", property = "deviceInterlockingId",
|
||||
typeHandler = ArrayIntegerTypeHandler.class),
|
||||
@Result(column = "device_interlocking_ip", property = "deviceInterlockingIp",
|
||||
typeHandler = ArrayStringTypeHandler.class),
|
||||
@Result(column = "ban_ips", property = "banIps",
|
||||
typeHandler = ArrayStringTypeHandler.class)
|
||||
})
|
||||
List<DeviceInterlockingCmd> selectByProbeIdAndStatus(@Param("probeId") Long probeId, @Param("cmdStatus") String cmdStatus);
|
||||
|
||||
/**
|
||||
* 插入指令
|
||||
*/
|
||||
@Insert("INSERT INTO device_interlocking_cmd (probe_id, probe_ip, device_interlocking_id, device_interlocking_ip, " +
|
||||
"ban_ips, ban_method, ban_type, cmd_status, ban_duration, create_time, update_time, " +
|
||||
"tenant_id, create_dept, create_by, remark, ban_operation_type) " +
|
||||
"VALUES (#{probeId}, #{probeIp}, ARRAY[:ids], ARRAY[:ips], ARRAY[:banIps], " +
|
||||
"#{banMethod}, #{banType}, #{cmdStatus}, #{banDuration}, NOW(), NOW(), " +
|
||||
"#{tenantId}, #{createDept}, #{createBy}, #{remark}, #{banOperationType})")
|
||||
@Options(useGeneratedKeys = true, keyProperty = "id")
|
||||
int insert(DeviceInterlockingCmd cmd);
|
||||
|
||||
/**
|
||||
* 更新指令状态
|
||||
* @param id 指令ID
|
||||
* @param cmdStatus 新状态
|
||||
* @return 影响行数
|
||||
*/
|
||||
@Update("UPDATE device_interlocking_cmd SET cmd_status = #{cmdStatus}, update_time = NOW() WHERE id = #{id}")
|
||||
int updateStatus(@Param("id") Long id, @Param("cmdStatus") String cmdStatus);
|
||||
|
||||
/**
|
||||
* 更新指令状态为执行中
|
||||
*/
|
||||
@Update("UPDATE device_interlocking_cmd SET cmd_status = '2', update_time = NOW() WHERE id = #{id}")
|
||||
int updateStatusToExecuting(@Param("id") Long id);
|
||||
|
||||
/**
|
||||
* 更新指令状态为执行完成
|
||||
*/
|
||||
@Update("UPDATE device_interlocking_cmd SET cmd_status = '1', update_time = NOW() WHERE id = #{id}")
|
||||
int updateStatusToCompleted(@Param("id") Long id);
|
||||
|
||||
/**
|
||||
* 更新指令状态为执行失败
|
||||
*/
|
||||
@Update("UPDATE device_interlocking_cmd SET cmd_status = '3', update_time = NOW() WHERE id = #{id}")
|
||||
int updateStatusToFailed(@Param("id") Long id);
|
||||
|
||||
/**
|
||||
* 根据多个ID查询
|
||||
*/
|
||||
@Select("<script>" +
|
||||
"SELECT * FROM device_interlocking_cmd WHERE id IN " +
|
||||
"<foreach collection='ids' item='id' open='(' separator=',' close=')'>" +
|
||||
"#{id}" +
|
||||
"</foreach>" +
|
||||
"</script>")
|
||||
@Results({
|
||||
@Result(column = "device_interlocking_id", property = "deviceInterlockingId",
|
||||
typeHandler = ArrayIntegerTypeHandler.class),
|
||||
@Result(column = "device_interlocking_ip", property = "deviceInterlockingIp",
|
||||
typeHandler = ArrayStringTypeHandler.class),
|
||||
@Result(column = "ban_ips", property = "banIps",
|
||||
typeHandler = ArrayStringTypeHandler.class)
|
||||
})
|
||||
List<DeviceInterlockingCmd> selectByIds(@Param("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 查询所有指令
|
||||
*/
|
||||
@Select("SELECT * FROM device_interlocking_cmd ORDER BY create_time DESC")
|
||||
@Results({
|
||||
@Result(column = "device_interlocking_id", property = "deviceInterlockingId",
|
||||
typeHandler = ArrayIntegerTypeHandler.class),
|
||||
@Result(column = "device_interlocking_ip", property = "deviceInterlockingIp",
|
||||
typeHandler = ArrayStringTypeHandler.class),
|
||||
@Result(column = "ban_ips", property = "banIps",
|
||||
typeHandler = ArrayStringTypeHandler.class)
|
||||
})
|
||||
List<DeviceInterlockingCmd> selectAll();
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.common.mapper;
|
||||
|
||||
import com.common.entity.DeviceInterlockingLog;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface DeviceInterlockingLogMapper {
|
||||
|
||||
/**
|
||||
* 根据ID查询
|
||||
*/
|
||||
@Select("SELECT * FROM device_interlocking_log WHERE id = #{id}")
|
||||
DeviceInterlockingLog selectById(Long id);
|
||||
|
||||
/**
|
||||
* 根据指令ID查询
|
||||
*/
|
||||
@Select("SELECT * FROM device_interlocking_log WHERE device_interlocking_cmd_id = #{cmdId}")
|
||||
List<DeviceInterlockingLog> selectByCmdId(@Param("cmdId") Long cmdId);
|
||||
|
||||
/**
|
||||
* 插入记录
|
||||
*/
|
||||
@Insert("INSERT INTO device_interlocking_log (device_interlocking_cmd_id, device_interlocking_id, ban_ip, " +
|
||||
"device_name, ban_time, ban_method, ban_result, tenant_id, create_dept, create_by, " +
|
||||
"create_time, remark, resp_body, req_body) " +
|
||||
"VALUES (#{deviceInterlockingCmdId}, #{deviceInterlockingId}, #{banIp}, #{deviceName}, " +
|
||||
"#{banTime}, #{banMethod}, #{banResult}, #{tenantId}, #{createDept}, #{createBy}, " +
|
||||
"NOW(), #{remark}, #{respBody}, #{reqBody})")
|
||||
@Options(useGeneratedKeys = true, keyProperty = "id")
|
||||
int insert(DeviceInterlockingLog log);
|
||||
|
||||
/**
|
||||
* 批量插入记录
|
||||
*/
|
||||
@Insert("<script>" +
|
||||
"INSERT INTO device_interlocking_log (device_interlocking_cmd_id, device_interlocking_id, ban_ip, " +
|
||||
"device_name, ban_time, ban_method, ban_result, tenant_id, create_dept, create_by, " +
|
||||
"create_time, remark, resp_body, req_body) VALUES " +
|
||||
"<foreach collection='logs' item='item' separator=','>" +
|
||||
"(#{item.deviceInterlockingCmdId}, #{item.deviceInterlockingId}, #{item.banIp}, " +
|
||||
"#{item.deviceName}, #{item.banTime}, #{item.banMethod}, #{item.banResult}, " +
|
||||
"#{item.tenantId}, #{item.createDept}, #{item.createBy}, NOW(), " +
|
||||
"#{item.remark}, #{item.respBody}, #{item.reqBody})" +
|
||||
"</foreach>" +
|
||||
"</script>")
|
||||
int batchInsert(@Param("logs") List<DeviceInterlockingLog> logs);
|
||||
|
||||
/**
|
||||
* 查询所有记录
|
||||
*/
|
||||
@Select("SELECT * FROM device_interlocking_log ORDER BY create_time DESC")
|
||||
List<DeviceInterlockingLog> selectAll();
|
||||
|
||||
/**
|
||||
* 统计某指令的成功/失败数量
|
||||
*/
|
||||
@Select("SELECT ban_result, COUNT(*) as count FROM device_interlocking_log " +
|
||||
"WHERE device_interlocking_cmd_id = #{cmdId} GROUP BY ban_result")
|
||||
List<java.util.Map<String, Object>> countByCmdId(@Param("cmdId") Long cmdId);
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.common.mapper;
|
||||
|
||||
import com.common.entity.DeviceInterlocking;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface DeviceInterlockingMapper {
|
||||
|
||||
/**
|
||||
* 根据ID查询
|
||||
*/
|
||||
@Select("SELECT * FROM device_interlocking WHERE id = #{id}")
|
||||
DeviceInterlocking selectById(Long id);
|
||||
|
||||
/**
|
||||
* 根据部门ID查询联动设备
|
||||
*/
|
||||
@Select("SELECT * FROM device_interlocking WHERE dept_id = #{deptId}")
|
||||
List<DeviceInterlocking> selectByDeptId(@Param("deptId") String deptId);
|
||||
|
||||
/**
|
||||
* 根据厂商查询
|
||||
*/
|
||||
@Select("SELECT * FROM device_interlocking WHERE vendor = #{vendor}")
|
||||
List<DeviceInterlocking> selectByVendor(@Param("vendor") String vendor);
|
||||
|
||||
/**
|
||||
* 插入记录
|
||||
*/
|
||||
@Insert("INSERT INTO device_interlocking (device_name, vendor, dept_id, ban_limit, ip, api_url, " +
|
||||
"tenant_id, create_dept, create_by, create_time, update_time, remark, auth_username, auth_password) " +
|
||||
"VALUES (#{deviceName}, #{vendor}, #{deptId}, #{banLimit}, #{ip}, #{apiUrl}, " +
|
||||
"#{tenantId}, #{createDept}, #{createBy}, NOW(), NOW(), #{remark}, #{authUsername}, #{authPassword})")
|
||||
@Options(useGeneratedKeys = true, keyProperty = "id")
|
||||
int insert(DeviceInterlocking device);
|
||||
|
||||
/**
|
||||
* 更新记录
|
||||
*/
|
||||
@Update("UPDATE device_interlocking SET device_name = #{deviceName}, vendor = #{vendor}, " +
|
||||
"dept_id = #{deptId}, ban_limit = #{banLimit}, ip = #{ip}, api_url = #{apiUrl}, " +
|
||||
"update_time = NOW(), remark = #{remark}, auth_username = #{authUsername}, " +
|
||||
"auth_password = #{authPassword} WHERE id = #{id}")
|
||||
int update(DeviceInterlocking device);
|
||||
|
||||
/**
|
||||
* 查询所有记录
|
||||
*/
|
||||
@Select("SELECT * FROM device_interlocking ORDER BY create_time DESC")
|
||||
List<DeviceInterlocking> selectAll();
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.common.mapper;
|
||||
|
||||
import com.common.entity.WecomNotification;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
|
||||
/**
|
||||
* 微信通知 Mapper 接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface WecomNotificationMapper {
|
||||
|
||||
/**
|
||||
* 插入单条记录(使用序列生成ID)
|
||||
*/
|
||||
@Insert("INSERT INTO wecom_notification (" +
|
||||
"wecom_notification_id, user_id, wecom_notification_name, wecom_notification_ip, " +
|
||||
"wecom_notification_type, wecom_notification_level, wecom_notification_content, " +
|
||||
"wecom_notification_time, tenant_id, create_dept, create_by, create_time, " +
|
||||
"update_by, update_time, remark, wecom_notification_status" +
|
||||
") VALUES (" +
|
||||
"nextval('seq_wecom_notification'), #{userId}, #{wecomNotificationName}, #{wecomNotificationIp}, " +
|
||||
"#{wecomNotificationType}, #{wecomNotificationLevel}, #{wecomNotificationContent}, " +
|
||||
"#{wecomNotificationTime}, #{tenantId}, #{createDept}, #{createBy}, #{createTime}, " +
|
||||
"#{updateBy}, #{updateTime}, #{remark}, #{wecomNotificationStatus}" +
|
||||
")")
|
||||
@SelectKey(statement = "SELECT currval('seq_wecom_notification')", keyProperty = "wecomNotificationId", resultType = Long.class, before = false)
|
||||
int insert(WecomNotification notification);
|
||||
|
||||
/**
|
||||
* 根据通知ID查询
|
||||
*/
|
||||
@Select("SELECT * FROM wecom_notification WHERE wecom_notification_id = #{wecomNotificationId}")
|
||||
WecomNotification selectById(@Param("wecomNotificationId") Long wecomNotificationId);
|
||||
|
||||
/**
|
||||
* 查询未发送的通知列表
|
||||
*/
|
||||
@Select("SELECT * FROM wecom_notification WHERE wecom_notification_status = '1' ORDER BY create_time DESC")
|
||||
java.util.List<WecomNotification> selectUnsentNotifications();
|
||||
|
||||
/**
|
||||
* 更新通知状态
|
||||
*/
|
||||
@Update("UPDATE wecom_notification SET wecom_notification_status = #{status}, update_time = NOW() " +
|
||||
"WHERE wecom_notification_id = #{wecomNotificationId}")
|
||||
int updateStatus(@Param("wecomNotificationId") Long wecomNotificationId, @Param("status") String status);
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.common.schedule;
|
||||
|
||||
import com.common.service.AlarmHealthCheckService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 告警健康检查定时任务
|
||||
* 每5分钟巡检告警表和告警日志表
|
||||
*/
|
||||
@Component
|
||||
public class AlarmHealthCheckScheduler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AlarmHealthCheckScheduler.class);
|
||||
|
||||
@Autowired
|
||||
private AlarmHealthCheckService alarmHealthCheckService;
|
||||
|
||||
/**
|
||||
* 每5分钟执行一次告警健康检查
|
||||
* 巡检告警表 alarm 和告警日志表 alarm_visit
|
||||
*/
|
||||
@Scheduled(cron = "0 */5 * * * ?")
|
||||
public void scheduledHealthCheck() {
|
||||
logger.info("========== 开始执行告警健康检查 ==========");
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
boolean hasAlarm = alarmHealthCheckService.performHealthCheck();
|
||||
|
||||
long elapsedTime = System.currentTimeMillis() - startTime;
|
||||
|
||||
if (hasAlarm) {
|
||||
logger.warn("告警健康检查完成, 发现异常数据, 耗时: {}ms", elapsedTime);
|
||||
} else {
|
||||
logger.info("告警健康检查完成, 所有表数据正常, 耗时: {}ms", elapsedTime);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("告警健康检查执行异常: {}", e.getMessage(), e);
|
||||
}
|
||||
|
||||
logger.info("========== 告警健康检查任务结束 ==========");
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发健康检查(供其他服务调用)
|
||||
* @return 是否有异常
|
||||
*/
|
||||
public boolean manualHealthCheck() {
|
||||
logger.info("手动触发告警健康检查");
|
||||
return alarmHealthCheckService.performHealthCheck();
|
||||
}
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
package com.common.service;
|
||||
|
||||
import com.common.entity.WecomNotification;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 告警健康检查服务
|
||||
* 巡检告警表和告警日志表是否有数据
|
||||
*/
|
||||
@Service
|
||||
public class AlarmHealthCheckService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AlarmHealthCheckService.class);
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
private WecomNotificationService wecomNotificationService;
|
||||
|
||||
@Value("${alarm.health-check.alarm-hours:2}")
|
||||
private int alarmHoursThreshold;
|
||||
|
||||
@Value("${alarm.health-check.alarm-visit-hours:4}")
|
||||
private int alarmVisitHoursThreshold;
|
||||
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
/**
|
||||
* 执行告警健康检查
|
||||
* @return 是否有异常
|
||||
*/
|
||||
public boolean performHealthCheck() {
|
||||
boolean hasAlarm = false;
|
||||
|
||||
// 1. 检查告警表 alarm
|
||||
boolean alarmTableNormal = checkAlarmTable();
|
||||
if (!alarmTableNormal) {
|
||||
hasAlarm = true;
|
||||
generateAlarmNotification("alarm", alarmHoursThreshold);
|
||||
}
|
||||
|
||||
// 2. 检查告警日志表 alarm_visit
|
||||
boolean alarmVisitTableNormal = checkAlarmVisitTable();
|
||||
if (!alarmVisitTableNormal) {
|
||||
hasAlarm = true;
|
||||
generateAlarmNotification("alarm_visit", alarmVisitHoursThreshold);
|
||||
}
|
||||
|
||||
return hasAlarm;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查告警表 alarm_yyyyMMdd 最近是否无数据
|
||||
* @return true=正常有数据, false=异常无数据
|
||||
*/
|
||||
public boolean checkAlarmTable() {
|
||||
String partitionDate = LocalDateTime.now().format(DATE_FORMATTER);
|
||||
String tableName = "alarm_" + partitionDate;
|
||||
|
||||
String sql = "SELECT COUNT(*) FROM " + tableName + " WHERE created_at >= NOW() - INTERVAL '" + alarmHoursThreshold + " hours'";
|
||||
|
||||
try {
|
||||
Long count = jdbcTemplate.queryForObject(sql, Long.class);
|
||||
boolean hasData = count != null && count > 0;
|
||||
|
||||
logger.info("告警表 {} 健康检查: {}小时内数据量={}, 状态={}",
|
||||
tableName, alarmHoursThreshold, count, hasData ? "正常" : "异常");
|
||||
|
||||
return hasData;
|
||||
} catch (Exception e) {
|
||||
logger.error("检查告警表 {} 失败: {}", tableName, e.getMessage());
|
||||
// 表不存在或查询失败,认为异常
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查告警日志表 alarm_visit_yyyyMMdd 最近是否无数据
|
||||
* @return true=正常有数据, false=异常无数据
|
||||
*/
|
||||
public boolean checkAlarmVisitTable() {
|
||||
String partitionDate = LocalDateTime.now().format(DATE_FORMATTER);
|
||||
String tableName = "alarm_visit_" + partitionDate;
|
||||
|
||||
String sql = "SELECT COUNT(*) FROM " + tableName + " WHERE created_at >= NOW() - INTERVAL '" + alarmVisitHoursThreshold + " hours'";
|
||||
|
||||
try {
|
||||
Long count = jdbcTemplate.queryForObject(sql, Long.class);
|
||||
boolean hasData = count != null && count > 0;
|
||||
|
||||
logger.info("告警日志表 {} 健康检查: {}小时内数据量={}, 状态={}",
|
||||
tableName, alarmVisitHoursThreshold, count, hasData ? "正常" : "异常");
|
||||
|
||||
return hasData;
|
||||
} catch (Exception e) {
|
||||
logger.error("检查告警日志表 {} 失败: {}", tableName, e.getMessage());
|
||||
// 表不存在或查询失败,认为异常
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成告警通知并插入微信通知表
|
||||
*
|
||||
* @param tableType 表类型(alarm 或 alarm_visit)
|
||||
* @param hoursThreshold 小时阈值
|
||||
*/
|
||||
public void generateAlarmNotification(String tableType, int hoursThreshold) {
|
||||
String tableName = tableType + "_" + LocalDateTime.now().format(DATE_FORMATTER);
|
||||
String content = String.format(
|
||||
"【数据巡检告警】%n" +
|
||||
"表名: %s%n" +
|
||||
"告警时间: %s%n" +
|
||||
"告警描述: 最近%d小时内无新数据%n" +
|
||||
"建议: 请检查数据采集服务是否正常运行%n" +
|
||||
"状态: 需要人工介入检查",
|
||||
tableName,
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
|
||||
hoursThreshold
|
||||
);
|
||||
|
||||
WecomNotification notification = wecomNotificationService.sendAlert(
|
||||
"数据巡检告警-" + tableName,
|
||||
"alarm_health_check",
|
||||
"3", // 高危
|
||||
content,
|
||||
null
|
||||
);
|
||||
|
||||
logger.warn("生成告警通知: 表={}, 通知ID={}", tableName, notification.getWecomNotificationId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信通知告警数据插入函数方法
|
||||
* 提供给其他模块在运行有异常的情况下调用
|
||||
*
|
||||
* @param alertName 告警名称
|
||||
* @param alertType 告警类型
|
||||
* @param alertLevel 告警等级(1:低, 2:中, 3:高, 4:紧急)
|
||||
* @param alertContent 告警内容
|
||||
* @return 通知实体
|
||||
*/
|
||||
public WecomNotification insertWecomAlert(String alertName, String alertType,
|
||||
String alertLevel, String alertContent) {
|
||||
return wecomNotificationService.sendAlert(alertName, alertType, alertLevel, alertContent, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速插入告警通知(简化版)
|
||||
*
|
||||
* @param alertType 告警类型
|
||||
* @param alertContent 告警内容
|
||||
* @return 通知实体
|
||||
*/
|
||||
public WecomNotification insertWecomAlert(String alertType, String alertContent) {
|
||||
return wecomNotificationService.sendAlert(alertType, alertContent);
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.common.service;
|
||||
|
||||
import com.common.entity.DeviceInterlockingCmd;
|
||||
import com.common.mapper.DeviceInterlockingCmdMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class DeviceInterlockingCmdService {
|
||||
|
||||
@Autowired
|
||||
private DeviceInterlockingCmdMapper cmdMapper;
|
||||
|
||||
/**
|
||||
* 根据ID查询
|
||||
*/
|
||||
public DeviceInterlockingCmd selectById(Long id) {
|
||||
return cmdMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询待执行的指令
|
||||
*/
|
||||
public List<DeviceInterlockingCmd> selectPendingCommands(Long probeId) {
|
||||
return cmdMapper.selectPendingCommands(probeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据探针ID和状态查询
|
||||
*/
|
||||
public List<DeviceInterlockingCmd> selectByProbeIdAndStatus(Long probeId, String cmdStatus) {
|
||||
return cmdMapper.selectByProbeIdAndStatus(probeId, cmdStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入指令
|
||||
*/
|
||||
public int insert(DeviceInterlockingCmd cmd) {
|
||||
return cmdMapper.insert(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指令状态
|
||||
*/
|
||||
public int updateStatus(Long id, String cmdStatus) {
|
||||
return cmdMapper.updateStatus(id, cmdStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指令状态为执行中
|
||||
*/
|
||||
public int updateStatusToExecuting(Long id) {
|
||||
return cmdMapper.updateStatusToExecuting(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指令状态为执行完成
|
||||
*/
|
||||
public int updateStatusToCompleted(Long id) {
|
||||
return cmdMapper.updateStatusToCompleted(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指令状态为执行失败
|
||||
*/
|
||||
public int updateStatusToFailed(Long id) {
|
||||
return cmdMapper.updateStatusToFailed(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有指令
|
||||
*/
|
||||
public List<DeviceInterlockingCmd> selectAll() {
|
||||
return cmdMapper.selectAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据多个ID查询
|
||||
*/
|
||||
public List<DeviceInterlockingCmd> selectByIds(List<Long> ids) {
|
||||
return cmdMapper.selectByIds(ids);
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.common.service;
|
||||
|
||||
import com.common.entity.DeviceInterlockingLog;
|
||||
import com.common.mapper.DeviceInterlockingLogMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class DeviceInterlockingLogService {
|
||||
|
||||
@Autowired
|
||||
private DeviceInterlockingLogMapper logMapper;
|
||||
|
||||
/**
|
||||
* 根据ID查询
|
||||
*/
|
||||
public DeviceInterlockingLog selectById(Long id) {
|
||||
return logMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指令ID查询
|
||||
*/
|
||||
public List<DeviceInterlockingLog> selectByCmdId(Long cmdId) {
|
||||
return logMapper.selectByCmdId(cmdId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入记录
|
||||
*/
|
||||
public int insert(DeviceInterlockingLog log) {
|
||||
if (log.getBanTime() == null) {
|
||||
log.setBanTime(OffsetDateTime.now());
|
||||
}
|
||||
return logMapper.insert(log);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入记录
|
||||
*/
|
||||
public int batchInsert(List<DeviceInterlockingLog> logs) {
|
||||
if (logs != null && !logs.isEmpty()) {
|
||||
for (DeviceInterlockingLog log : logs) {
|
||||
if (log.getBanTime() == null) {
|
||||
log.setBanTime(OffsetDateTime.now());
|
||||
}
|
||||
}
|
||||
}
|
||||
return logMapper.batchInsert(logs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有记录
|
||||
*/
|
||||
public List<DeviceInterlockingLog> selectAll() {
|
||||
return logMapper.selectAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计某指令的成功/失败数量
|
||||
*/
|
||||
public List<java.util.Map<String, Object>> countByCmdId(Long cmdId) {
|
||||
return logMapper.countByCmdId(cmdId);
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.common.service;
|
||||
|
||||
import com.common.entity.DeviceInterlocking;
|
||||
import com.common.mapper.DeviceInterlockingMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class DeviceInterlockingService {
|
||||
|
||||
@Autowired
|
||||
private DeviceInterlockingMapper interlockingMapper;
|
||||
|
||||
/**
|
||||
* 根据ID查询
|
||||
*/
|
||||
public DeviceInterlocking selectById(Long id) {
|
||||
return interlockingMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门ID查询联动设备
|
||||
*/
|
||||
public List<DeviceInterlocking> selectByDeptId(String deptId) {
|
||||
return interlockingMapper.selectByDeptId(deptId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据厂商查询
|
||||
*/
|
||||
public List<DeviceInterlocking> selectByVendor(String vendor) {
|
||||
return interlockingMapper.selectByVendor(vendor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入记录
|
||||
*/
|
||||
public int insert(DeviceInterlocking device) {
|
||||
return interlockingMapper.insert(device);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新记录
|
||||
*/
|
||||
public int update(DeviceInterlocking device) {
|
||||
return interlockingMapper.update(device);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有记录
|
||||
*/
|
||||
public List<DeviceInterlocking> selectAll() {
|
||||
return interlockingMapper.selectAll();
|
||||
}
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
package com.common.service;
|
||||
|
||||
import com.common.entity.WecomNotification;
|
||||
import com.common.mapper.WecomNotificationMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 微信通知服务类
|
||||
*/
|
||||
@Service
|
||||
public class WecomNotificationService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(WecomNotificationService.class);
|
||||
|
||||
@Autowired
|
||||
private WecomNotificationMapper wecomNotificationMapper;
|
||||
|
||||
/**
|
||||
* 插入微信通知
|
||||
*
|
||||
* @param notification 通知实体
|
||||
* @return 影响的行数
|
||||
*/
|
||||
public int insert(WecomNotification notification) {
|
||||
try {
|
||||
if (notification.getCreateTime() == null) {
|
||||
notification.setCreateTime(LocalDateTime.now());
|
||||
}
|
||||
if (notification.getWecomNotificationTime() == null) {
|
||||
notification.setWecomNotificationTime(LocalDateTime.now());
|
||||
}
|
||||
if (notification.getWecomNotificationStatus() == null) {
|
||||
notification.setWecomNotificationStatus("1"); // 默认未发送
|
||||
}
|
||||
if (notification.getTenantId() == null) {
|
||||
notification.setTenantId("000000");
|
||||
}
|
||||
int rows = wecomNotificationMapper.insert(notification);
|
||||
logger.info("插入微信通知成功, ID: {}, 类型: {}, 内容: {}",
|
||||
notification.getWecomNotificationId(),
|
||||
notification.getWecomNotificationType(),
|
||||
notification.getWecomNotificationName());
|
||||
return rows;
|
||||
} catch (Exception e) {
|
||||
logger.error("插入微信通知失败: {}", e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询
|
||||
*/
|
||||
public WecomNotification selectById(Long id) {
|
||||
return wecomNotificationMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询未发送的通知列表
|
||||
*/
|
||||
public java.util.List<WecomNotification> selectUnsentNotifications() {
|
||||
return wecomNotificationMapper.selectUnsentNotifications();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新通知状态
|
||||
*
|
||||
* @param id 通知ID
|
||||
* @param status 状态(0:已发送, 1:未发送)
|
||||
* @return 影响的行数
|
||||
*/
|
||||
public int updateStatus(Long id, String status) {
|
||||
return wecomNotificationMapper.updateStatus(id, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送微信通知告警
|
||||
* 提供给其他模块在运行异常时调用
|
||||
*
|
||||
* @param name 通知名称
|
||||
* @param type 通知类型(如:alarm_health_check)
|
||||
* @param level 通知等级(1:低, 2:中, 3:高, 4:紧急)
|
||||
* @param content 通知内容
|
||||
* @param ip 关联IP(可选)
|
||||
* @return 通知实体
|
||||
*/
|
||||
public WecomNotification sendAlert(String name, String type, String level, String content, String ip) {
|
||||
WecomNotification notification = new WecomNotification();
|
||||
notification.setWecomNotificationName(name);
|
||||
notification.setWecomNotificationType(type);
|
||||
notification.setWecomNotificationLevel(level);
|
||||
notification.setWecomNotificationContent(content);
|
||||
notification.setWecomNotificationIp(ip);
|
||||
notification.setWecomNotificationTime(LocalDateTime.now());
|
||||
notification.setWecomNotificationStatus("1"); // 未发送
|
||||
notification.setTenantId("000000");
|
||||
notification.setCreateTime(LocalDateTime.now());
|
||||
|
||||
insert(notification);
|
||||
|
||||
logger.warn("发送微信告警通知 - 名称: {}, 类型: {}, 等级: {}, 内容: {}",
|
||||
name, type, level, content);
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送告警通知(简化版本)
|
||||
*
|
||||
* @param alertType 告警类型
|
||||
* @param alertContent 告警内容
|
||||
* @return 通知实体
|
||||
*/
|
||||
public WecomNotification sendAlert(String alertType, String alertContent) {
|
||||
return sendAlert(alertType, alertType, "3", alertContent, null);
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.haobang.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* API-KEY认证拦截器
|
||||
*/
|
||||
@Component
|
||||
public class ApiKeyInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Value("${interlocking.api-key:}")
|
||||
private String configuredApiKey;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
// 放行CORS预检请求
|
||||
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String requestApiKey = request.getHeader("X-API-KEY");
|
||||
|
||||
// 如果配置了API-KEY,则进行校验
|
||||
if (configuredApiKey != null && !configuredApiKey.isEmpty()) {
|
||||
if (requestApiKey == null || requestApiKey.isEmpty()) {
|
||||
sendUnauthorized(response, "API-KEY header is missing");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!configuredApiKey.equals(requestApiKey)) {
|
||||
sendUnauthorized(response, "Invalid API-KEY");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void sendUnauthorized(HttpServletResponse response, String message) throws Exception {
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
response.getWriter().write("{\"code\":401,\"message\":\"" + message + "\"}");
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.haobang.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* Web MVC配置类
|
||||
*/
|
||||
@Configuration
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Autowired
|
||||
private ApiKeyInterceptor apiKeyInterceptor;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 配置API-KEY拦截器,只拦截联动相关的接口
|
||||
registry.addInterceptor(apiKeyInterceptor)
|
||||
.addPathPatterns("/interlocking/**")
|
||||
.excludePathPatterns("/interlocking/health");
|
||||
}
|
||||
}
|
||||
+417
@@ -0,0 +1,417 @@
|
||||
package com.haobang.controller;
|
||||
|
||||
import com.common.entity.DeviceInterlockingCmd;
|
||||
import com.common.entity.DeviceInterlockingLog;
|
||||
import com.common.entity.DeviceInterlocking;
|
||||
import com.common.service.DeviceInterlockingCmdService;
|
||||
import com.common.service.DeviceInterlockingLogService;
|
||||
import com.common.service.DeviceInterlockingService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 探针联动控制器
|
||||
* 提供REST API接口给syslog-serve模块调用
|
||||
* API-KEY认证机制
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/interlocking")
|
||||
public class InterlockingController {
|
||||
|
||||
@Autowired
|
||||
private DeviceInterlockingCmdService cmdService;
|
||||
|
||||
@Autowired
|
||||
private DeviceInterlockingLogService logService;
|
||||
|
||||
@Autowired
|
||||
private DeviceInterlockingService interlockingService;
|
||||
|
||||
/**
|
||||
* 健康检查接口(不需要API-KEY认证)
|
||||
*/
|
||||
@GetMapping("/health")
|
||||
public ResponseEntity<Map<String, Object>> health() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 200);
|
||||
result.put("message", "OK");
|
||||
result.put("service", "interlocking-api");
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
// ==================== 封禁指令接口 ====================
|
||||
|
||||
/**
|
||||
* 1.1 获取待执行的封禁指令记录
|
||||
* GET /interlocking/cmd/pending?probeId=1
|
||||
*/
|
||||
@GetMapping("/cmd/pending")
|
||||
public ResponseEntity<Map<String, Object>> getPendingCommands(@RequestParam Long probeId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
List<DeviceInterlockingCmd> commands = cmdService.selectPendingCommands(probeId);
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", commands);
|
||||
result.put("total", commands.size());
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "获取待执行指令失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 1.2 获取指定状态的封禁指令记录
|
||||
* GET /interlocking/cmd?probeId=1&cmdStatus=0
|
||||
*/
|
||||
@GetMapping("/cmd")
|
||||
public ResponseEntity<Map<String, Object>> getCommands(
|
||||
@RequestParam Long probeId,
|
||||
@RequestParam(required = false) String cmdStatus) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
List<DeviceInterlockingCmd> commands;
|
||||
if (cmdStatus != null && !cmdStatus.isEmpty()) {
|
||||
commands = cmdService.selectByProbeIdAndStatus(probeId, cmdStatus);
|
||||
} else {
|
||||
commands = cmdService.selectPendingCommands(probeId);
|
||||
}
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", commands);
|
||||
result.put("total", commands.size());
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "获取指令失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 1.3 获取单个指令详情
|
||||
* GET /interlocking/cmd/{id}
|
||||
*/
|
||||
@GetMapping("/cmd/{id}")
|
||||
public ResponseEntity<Map<String, Object>> getCommandById(@PathVariable Long id) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
DeviceInterlockingCmd command = cmdService.selectById(id);
|
||||
if (command == null) {
|
||||
result.put("code", 404);
|
||||
result.put("message", "指令不存在");
|
||||
return ResponseEntity.status(404).body(result);
|
||||
}
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", command);
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "获取指令详情失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 1.4 创建新的封禁指令
|
||||
* POST /interlocking/cmd
|
||||
*/
|
||||
@PostMapping("/cmd")
|
||||
public ResponseEntity<Map<String, Object>> createCommand(@RequestBody DeviceInterlockingCmd cmd) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
// 设置默认状态为待执行
|
||||
if (cmd.getCmdStatus() == null || cmd.getCmdStatus().isEmpty()) {
|
||||
cmd.setCmdStatus("0");
|
||||
}
|
||||
int rows = cmdService.insert(cmd);
|
||||
result.put("code", 200);
|
||||
result.put("message", "指令创建成功");
|
||||
result.put("data", rows);
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "创建指令失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 指令状态更新接口 ====================
|
||||
|
||||
/**
|
||||
* 2.1 更新封禁指令状态为执行中
|
||||
* PUT /interlocking/cmd/{id}/status/executing
|
||||
*/
|
||||
@PutMapping("/cmd/{id}/status/executing")
|
||||
public ResponseEntity<Map<String, Object>> updateStatusToExecuting(@PathVariable Long id) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
int rows = cmdService.updateStatusToExecuting(id);
|
||||
if (rows > 0) {
|
||||
result.put("code", 200);
|
||||
result.put("message", "状态已更新为执行中");
|
||||
result.put("data", rows);
|
||||
} else {
|
||||
result.put("code", 404);
|
||||
result.put("message", "指令不存在");
|
||||
}
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "更新状态失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 2.2 更新封禁指令状态为执行完成
|
||||
* PUT /interlocking/cmd/{id}/status/completed
|
||||
*/
|
||||
@PutMapping("/cmd/{id}/status/completed")
|
||||
public ResponseEntity<Map<String, Object>> updateStatusToCompleted(@PathVariable Long id) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
int rows = cmdService.updateStatusToCompleted(id);
|
||||
if (rows > 0) {
|
||||
result.put("code", 200);
|
||||
result.put("message", "状态已更新为执行完成");
|
||||
result.put("data", rows);
|
||||
} else {
|
||||
result.put("code", 404);
|
||||
result.put("message", "指令不存在");
|
||||
}
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "更新状态失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 2.3 更新封禁指令状态为执行失败
|
||||
* PUT /interlocking/cmd/{id}/status/failed
|
||||
*/
|
||||
@PutMapping("/cmd/{id}/status/failed")
|
||||
public ResponseEntity<Map<String, Object>> updateStatusToFailed(@PathVariable Long id) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
int rows = cmdService.updateStatusToFailed(id);
|
||||
if (rows > 0) {
|
||||
result.put("code", 200);
|
||||
result.put("message", "状态已更新为执行失败");
|
||||
result.put("data", rows);
|
||||
} else {
|
||||
result.put("code", 404);
|
||||
result.put("message", "指令不存在");
|
||||
}
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "更新状态失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 2.4 批量更新封禁指令状态
|
||||
* PUT /interlocking/cmd/status
|
||||
*/
|
||||
@PutMapping("/cmd/status")
|
||||
public ResponseEntity<Map<String, Object>> batchUpdateStatus(@RequestBody Map<String, Object> request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Long> ids = (List<Long>) request.get("ids");
|
||||
String cmdStatus = (String) request.get("cmdStatus");
|
||||
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
result.put("code", 400);
|
||||
result.put("message", "指令ID列表不能为空");
|
||||
return ResponseEntity.badRequest().body(result);
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
for (Long id : ids) {
|
||||
total += cmdService.updateStatus(id, cmdStatus);
|
||||
}
|
||||
|
||||
result.put("code", 200);
|
||||
result.put("message", "批量更新成功");
|
||||
result.put("data", total);
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "批量更新状态失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 封禁记录接口 ====================
|
||||
|
||||
/**
|
||||
* 3.1 批量插入封禁记录
|
||||
* POST /interlocking/log/batch
|
||||
*/
|
||||
@PostMapping("/log/batch")
|
||||
public ResponseEntity<Map<String, Object>> batchInsertLog(@RequestBody Map<String, Object> request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
// Spring无法直接将List<LinkedHashMap>转为List<DeviceInterlockingLog>
|
||||
// 需要手动转换
|
||||
Object logsObj = request.get("logs");
|
||||
List<DeviceInterlockingLog> logs;
|
||||
if (logsObj instanceof List) {
|
||||
logs = ((List<?>) logsObj).stream()
|
||||
.map(item -> convertToDeviceInterlockingLog(item))
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
result.put("code", 400);
|
||||
result.put("message", "logs字段格式错误,应为数组");
|
||||
return ResponseEntity.badRequest().body(result);
|
||||
}
|
||||
|
||||
if (logs == null || logs.isEmpty()) {
|
||||
result.put("code", 400);
|
||||
result.put("message", "封禁记录列表不能为空");
|
||||
return ResponseEntity.badRequest().body(result);
|
||||
}
|
||||
|
||||
int rows = logService.batchInsert(logs);
|
||||
result.put("code", 200);
|
||||
result.put("message", "批量插入成功");
|
||||
result.put("data", rows);
|
||||
result.put("total", logs.size());
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "批量插入记录失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Map转换为DeviceInterlockingLog实体
|
||||
*/
|
||||
private DeviceInterlockingLog convertToDeviceInterlockingLog(Object item) {
|
||||
DeviceInterlockingLog log = new DeviceInterlockingLog();
|
||||
if (item instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) item;
|
||||
|
||||
if (map.get("id") != null) log.setId(((Number) map.get("id")).longValue());
|
||||
if (map.get("deviceInterlockingCmdId") != null) log.setDeviceInterlockingCmdId(((Number) map.get("deviceInterlockingCmdId")).longValue());
|
||||
if (map.get("deviceInterlockingId") != null) log.setDeviceInterlockingId(((Number) map.get("deviceInterlockingId")).longValue());
|
||||
if (map.get("banIp") != null) log.setBanIp(String.valueOf(map.get("banIp")));
|
||||
if (map.get("deviceName") != null) log.setDeviceName(String.valueOf(map.get("deviceName")));
|
||||
if (map.get("banMethod") != null) log.setBanMethod(String.valueOf(map.get("banMethod")));
|
||||
if (map.get("banResult") != null) {
|
||||
Object banResult = map.get("banResult");
|
||||
if (banResult instanceof Number) {
|
||||
log.setBanResult(((Number) banResult).intValue());
|
||||
} else {
|
||||
log.setBanResult(Integer.parseInt(String.valueOf(banResult)));
|
||||
}
|
||||
}
|
||||
if (map.get("tenantId") != null) log.setTenantId(String.valueOf(map.get("tenantId")));
|
||||
if (map.get("createDept") != null) log.setCreateDept(((Number) map.get("createDept")).longValue());
|
||||
if (map.get("createBy") != null) log.setCreateBy(((Number) map.get("createBy")).longValue());
|
||||
if (map.get("remark") != null) log.setRemark(String.valueOf(map.get("remark")));
|
||||
if (map.get("respBody") != null) log.setRespBody(String.valueOf(map.get("respBody")));
|
||||
if (map.get("reqBody") != null) log.setReqBody(String.valueOf(map.get("reqBody")));
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* 3.2 获取封禁记录列表
|
||||
* GET /interlocking/log?cmdId=1
|
||||
*/
|
||||
@GetMapping("/log")
|
||||
public ResponseEntity<Map<String, Object>> getLogs(@RequestParam(required = false) Long cmdId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
List<DeviceInterlockingLog> logs;
|
||||
if (cmdId != null) {
|
||||
logs = logService.selectByCmdId(cmdId);
|
||||
} else {
|
||||
logs = logService.selectAll();
|
||||
}
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", logs);
|
||||
result.put("total", logs.size());
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "获取记录失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 联动设备接口 ====================
|
||||
|
||||
/**
|
||||
* 获取联动设备列表
|
||||
* GET /interlocking/device
|
||||
*/
|
||||
@GetMapping("/device")
|
||||
public ResponseEntity<Map<String, Object>> getDevices(
|
||||
@RequestParam(required = false) String deptId,
|
||||
@RequestParam(required = false) String vendor) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
List<DeviceInterlocking> devices;
|
||||
if (deptId != null && !deptId.isEmpty()) {
|
||||
devices = interlockingService.selectByDeptId(deptId);
|
||||
} else if (vendor != null && !vendor.isEmpty()) {
|
||||
devices = interlockingService.selectByVendor(vendor);
|
||||
} else {
|
||||
devices = interlockingService.selectAll();
|
||||
}
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", devices);
|
||||
result.put("total", devices.size());
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "获取设备失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个联动设备详情
|
||||
* GET /interlocking/device/{id}
|
||||
*/
|
||||
@GetMapping("/device/{id}")
|
||||
public ResponseEntity<Map<String, Object>> getDeviceById(@PathVariable Long id) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
DeviceInterlocking device = interlockingService.selectById(id);
|
||||
if (device == null) {
|
||||
result.put("code", 404);
|
||||
result.put("message", "设备不存在");
|
||||
return ResponseEntity.status(404).body(result);
|
||||
}
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", device);
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "获取设备详情失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,6 @@
|
||||
<version>1.4.2</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- json 框架 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
@@ -180,8 +179,29 @@
|
||||
<version>${pagehelper.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Hutool 核心工具库 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.27</version> <!-- 建议使用较新的稳定版本 -->
|
||||
</dependency>
|
||||
|
||||
<!-- Bouncy Castle 国密算法支持 -->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15to18</artifactId>
|
||||
<version>1.78</version> <!-- 兼容 Java 1.8 -->
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
package com.haobang.controller;
|
||||
|
||||
import com.haobang.interlocking.InterlockingService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 探针联动控制器
|
||||
* 提供手动触发封禁的REST API
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/interlocking")
|
||||
public class InterlockingController {
|
||||
|
||||
@Autowired
|
||||
private InterlockingService interlockingService;
|
||||
|
||||
/**
|
||||
* 手动封禁单个IP
|
||||
* POST /interlocking/block
|
||||
*
|
||||
* @param request 封禁请求参数
|
||||
* @return 执行结果
|
||||
*/
|
||||
@PostMapping("/block")
|
||||
public ResponseEntity<Map<String, Object>> blockIp(@RequestBody Map<String, Object> request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
String ip = (String) request.get("ip");
|
||||
String cmdType = (String) request.getOrDefault("cmdType", "add_blacklist");
|
||||
Integer age = request.containsKey("age") ? ((Number) request.get("age")).intValue() : -1;
|
||||
String reason = (String) request.getOrDefault("reason", "manual_block");
|
||||
|
||||
if (ip == null || ip.isEmpty()) {
|
||||
result.put("code", 400);
|
||||
result.put("message", "IP地址不能为空");
|
||||
return ResponseEntity.badRequest().body(result);
|
||||
}
|
||||
|
||||
Map<String, Object> response = interlockingService.manualBlock(ip, cmdType, age, reason);
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", response);
|
||||
return ResponseEntity.ok(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "封禁失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量封禁IP
|
||||
* POST /interlocking/block/batch
|
||||
*
|
||||
* @param request 批量封禁请求参数
|
||||
* @return 执行结果
|
||||
*/
|
||||
@PostMapping("/block/batch")
|
||||
public ResponseEntity<Map<String, Object>> batchBlockIp(@RequestBody Map<String, Object> request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> ips = (List<String>) request.get("ips");
|
||||
String cmdType = (String) request.getOrDefault("cmdType", "add_blacklist");
|
||||
Integer age = request.containsKey("age") ? ((Number) request.get("age")).intValue() : -1;
|
||||
String reason = (String) request.getOrDefault("reason", "manual_batch_block");
|
||||
|
||||
if (ips == null || ips.isEmpty()) {
|
||||
result.put("code", 400);
|
||||
result.put("message", "IP地址列表不能为空");
|
||||
return ResponseEntity.badRequest().body(result);
|
||||
}
|
||||
|
||||
Map<String, Object> response = interlockingService.batchManualBlock(ips, cmdType, age, reason);
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", response);
|
||||
result.put("total", ips.size());
|
||||
return ResponseEntity.ok(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "批量封禁失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从黑名单删除IP
|
||||
* DELETE /interlocking/blacklist/{ip}
|
||||
*/
|
||||
@DeleteMapping("/blacklist/{ip}")
|
||||
public ResponseEntity<Map<String, Object>> removeFromBlacklist(@PathVariable String ip) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
Map<String, Object> response = interlockingService.manualBlock(ip, "del_blacklist", -1, "");
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", response);
|
||||
return ResponseEntity.ok(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "删除黑名单失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量从黑名单删除IP
|
||||
* DELETE /interlocking/blacklist
|
||||
*/
|
||||
@DeleteMapping("/blacklist")
|
||||
public ResponseEntity<Map<String, Object>> batchRemoveFromBlacklist(@RequestBody Map<String, Object> request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> ips = (List<String>) request.get("ips");
|
||||
|
||||
if (ips == null || ips.isEmpty()) {
|
||||
result.put("code", 400);
|
||||
result.put("message", "IP地址列表不能为空");
|
||||
return ResponseEntity.badRequest().body(result);
|
||||
}
|
||||
|
||||
Map<String, Object> response = interlockingService.batchManualBlock(ips, "del_blacklist", -1, "");
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", response);
|
||||
result.put("total", ips.size());
|
||||
return ResponseEntity.ok(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "批量删除黑名单失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取联动服务状态
|
||||
* GET /interlocking/status
|
||||
*/
|
||||
@GetMapping("/status")
|
||||
public ResponseEntity<Map<String, Object>> getStatus() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
|
||||
Map<String, Object> status = new HashMap<>();
|
||||
status.put("enabled", interlockingService.isInterlockingEnabled());
|
||||
status.put("probeId", interlockingService.getProbeId());
|
||||
result.put("data", status);
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
result.put("code", 500);
|
||||
result.put("message", "获取状态失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 健康检查
|
||||
* GET /interlocking/health
|
||||
*/
|
||||
@GetMapping("/health")
|
||||
public ResponseEntity<Map<String, Object>> health() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 200);
|
||||
result.put("message", "OK");
|
||||
result.put("service", "interlocking-client");
|
||||
result.put("probeId", interlockingService.getProbeId());
|
||||
result.put("enabled", interlockingService.isInterlockingEnabled());
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
}
|
||||
+420
@@ -0,0 +1,420 @@
|
||||
package com.haobang.firewall;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.net.ProtocolException;
|
||||
|
||||
/**
|
||||
* 防火墙API客户端
|
||||
* 支持安恒信息-明御安全网关的黑名单/白名单操作
|
||||
*/
|
||||
@Component
|
||||
public class FirewallApiClient {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FirewallApiClient.class);
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
// 黑名单API配置
|
||||
@Value("${blacklist.api.url:https://103.43.84.11/api/v3/Objects/Blacklist}")
|
||||
private String blacklistApiUrl;
|
||||
|
||||
@Value("${blacklist.api.username:apt-admin103}")
|
||||
private String blacklistUsername;
|
||||
|
||||
@Value("${blacklist.api.password:C9W2xYgfc%SN1}")
|
||||
private String blacklistPassword;
|
||||
|
||||
// 白名单API配置
|
||||
@Value("${whitelist.api.url:https://103.43.84.11/api/v3/Policies/GlobalWhitelist}")
|
||||
private String whitelistApiUrl;
|
||||
|
||||
@Value("${whitelist.api.username:apt-admin103}")
|
||||
private String whitelistUsername;
|
||||
|
||||
@Value("${whitelist.api.password:C9W2xYgfc%SN1}")
|
||||
private String whitelistPassword;
|
||||
|
||||
@Value("${firewall.enabled:true}")
|
||||
private boolean firewallEnabled;
|
||||
|
||||
/**
|
||||
* 添加IP到黑名单
|
||||
* @param ip IP地址
|
||||
* @param age 生命周期(秒),-1表示永久
|
||||
* @param reason 原因/备注
|
||||
* @return 操作结果
|
||||
*/
|
||||
public FirewallResponse addToBlacklist(String ip, int age, String reason) {
|
||||
if (!firewallEnabled) {
|
||||
logger.info("[测试模式] 添加黑名单: ip={}, age={}, reason={}", ip, age, reason);
|
||||
return new FirewallResponse(true, "1", "测试模式-模拟成功");
|
||||
}
|
||||
|
||||
Map<String, Object> payload = new HashMap<>();
|
||||
payload.put("blist", ip);
|
||||
payload.put("age", String.valueOf(age));
|
||||
payload.put("enable", "1");
|
||||
if (reason != null && !reason.isEmpty()) {
|
||||
payload.put("reason", reason);
|
||||
}
|
||||
|
||||
return doPost(blacklistApiUrl, blacklistUsername, blacklistPassword, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加IP到黑名单
|
||||
* @param ips IP列表,每个元素包含 ip, age, reason
|
||||
* @return 操作结果
|
||||
*/
|
||||
public FirewallResponse batchAddToBlacklist(List<Map<String, String>> ips) {
|
||||
if (!firewallEnabled) {
|
||||
logger.info("[测试模式] 批量添加黑名单: {}", ips);
|
||||
return new FirewallResponse(true, "1", "测试模式-模拟成功");
|
||||
}
|
||||
|
||||
List<Map<String, String>> entries = new ArrayList<>();
|
||||
for (Map<String, String> ipInfo : ips) {
|
||||
Map<String, String> entry = new HashMap<>();
|
||||
entry.put("blist", ipInfo.get("ip"));
|
||||
entry.put("age", ipInfo.getOrDefault("age", "-1"));
|
||||
entry.put("enable", "1");
|
||||
if (ipInfo.containsKey("reason")) {
|
||||
entry.put("reason", ipInfo.get("reason"));
|
||||
}
|
||||
entries.add(entry);
|
||||
}
|
||||
|
||||
Map<String, Object> payload = new HashMap<>();
|
||||
payload.put("blist_entry", entries);
|
||||
|
||||
return doPost(blacklistApiUrl, blacklistUsername, blacklistPassword, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从黑名单删除IP
|
||||
* @param ip IP地址
|
||||
* @return 操作结果
|
||||
*/
|
||||
public FirewallResponse removeFromBlacklist(String ip) {
|
||||
if (!firewallEnabled) {
|
||||
logger.info("[测试模式] 删除黑名单: ip={}", ip);
|
||||
return new FirewallResponse(true, "1", "测试模式-模拟成功");
|
||||
}
|
||||
|
||||
String deleteUrl = blacklistApiUrl + "/blist/" + ip;
|
||||
return doDelete(deleteUrl, blacklistUsername, blacklistPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量从黑名单删除IP
|
||||
* @param ips IP地址列表
|
||||
* @return 操作结果
|
||||
*/
|
||||
public FirewallResponse batchRemoveFromBlacklist(List<String> ips) {
|
||||
if (!firewallEnabled) {
|
||||
logger.info("[测试模式] 批量删除黑名单: {}", ips);
|
||||
return new FirewallResponse(true, "1", "测试模式-模拟成功");
|
||||
}
|
||||
|
||||
List<Map<String, String>> entries = ips.stream()
|
||||
.map(ip -> {
|
||||
Map<String, String> entry = new HashMap<>();
|
||||
entry.put("blist", ip);
|
||||
return entry;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<String, Object> payload = new HashMap<>();
|
||||
payload.put("blist_entry", entries);
|
||||
|
||||
return doDelete(blacklistApiUrl, blacklistUsername, blacklistPassword, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加IP到白名单
|
||||
* @param ip IP地址
|
||||
* @param name 名称
|
||||
* @param desc 描述
|
||||
* @return 操作结果
|
||||
*/
|
||||
public FirewallResponse addToWhitelist(String ip, String name, String desc) {
|
||||
if (!firewallEnabled) {
|
||||
logger.info("[测试模式] 添加白名单: ip={}, name={}", ip, name);
|
||||
return new FirewallResponse(true, "1", "测试模式-模拟成功");
|
||||
}
|
||||
|
||||
List<Map<String, String>> addresses = new ArrayList<>();
|
||||
Map<String, String> address = new HashMap<>();
|
||||
address.put("address", ip);
|
||||
addresses.add(address);
|
||||
|
||||
Map<String, Object> payload = new HashMap<>();
|
||||
payload.put("enable", "1");
|
||||
payload.put("name", name);
|
||||
payload.put("desc", desc != null ? desc : "");
|
||||
payload.put("addr", addresses);
|
||||
|
||||
return doPost(whitelistApiUrl, whitelistUsername, whitelistPassword, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除白名单
|
||||
* @param name 白名单名称
|
||||
* @return 操作结果
|
||||
*/
|
||||
public FirewallResponse removeFromWhitelist(String name) {
|
||||
if (!firewallEnabled) {
|
||||
logger.info("[测试模式] 删除白名单: name={}", name);
|
||||
return new FirewallResponse(true, "1", "测试模式-模拟成功");
|
||||
}
|
||||
|
||||
String deleteUrl = whitelistApiUrl + "/name/" + name;
|
||||
return doDelete(deleteUrl, whitelistUsername, whitelistPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除白名单
|
||||
* @param names 白名单名称列表
|
||||
* @return 操作结果
|
||||
*/
|
||||
public FirewallResponse batchRemoveFromWhitelist(List<String> names) {
|
||||
if (!firewallEnabled) {
|
||||
logger.info("[测试模式] 批量删除白名单: {}", names);
|
||||
return new FirewallResponse(true, "1", "测试模式-模拟成功");
|
||||
}
|
||||
|
||||
List<Map<String, String>> nameList = names.stream()
|
||||
.map(name -> {
|
||||
Map<String, String> entry = new HashMap<>();
|
||||
entry.put("name", name);
|
||||
return entry;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<String, Object> payload = new HashMap<>();
|
||||
payload.put("name_list", nameList);
|
||||
|
||||
String batchDeleteUrl = whitelistApiUrl + "Batch";
|
||||
return doDelete(batchDeleteUrl, whitelistUsername, whitelistPassword, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行POST请求
|
||||
*/
|
||||
private FirewallResponse doPost(String urlStr, String username, String password, Map<String, Object> payload) {
|
||||
HttpURLConnection conn = null;
|
||||
try {
|
||||
URL url = new URL(urlStr);
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
setupConnection(conn, username, password, "POST");
|
||||
|
||||
// 发送请求体
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String jsonBody = mapper.writeValueAsString(payload);
|
||||
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
// 获取响应
|
||||
int responseCode = conn.getResponseCode();
|
||||
String response = readResponse(conn);
|
||||
|
||||
logger.info("POST请求响应: url={}, code={}, response={}", urlStr, responseCode, response);
|
||||
|
||||
// 解析响应
|
||||
JsonNode jsonNode = mapper.readTree(response);
|
||||
int code = jsonNode.has("code") ? jsonNode.get("code").asInt() : responseCode;
|
||||
String msg = jsonNode.has("msg") && !jsonNode.get("msg").isNull() ? jsonNode.get("msg").asText() : "";
|
||||
|
||||
return new FirewallResponse(code == 1, String.valueOf(code), msg, response);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("POST请求失败: url={}, error={}", urlStr, e.getMessage(), e);
|
||||
return new FirewallResponse(false, "-1", "请求失败: " + e.getMessage());
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行DELETE请求(无请求体)
|
||||
*/
|
||||
private FirewallResponse doDelete(String urlStr, String username, String password) {
|
||||
HttpURLConnection conn = null;
|
||||
try {
|
||||
URL url = new URL(urlStr);
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
setupConnection(conn, username, password, "DELETE");
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
String response = readResponse(conn);
|
||||
|
||||
logger.info("DELETE请求响应: url={}, code={}, response={}", urlStr, responseCode, response);
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode jsonNode = mapper.readTree(response);
|
||||
int code = jsonNode.has("code") ? jsonNode.get("code").asInt() : responseCode;
|
||||
String msg = jsonNode.has("msg") && !jsonNode.get("msg").isNull() ? jsonNode.get("msg").asText() : "";
|
||||
|
||||
return new FirewallResponse(code == 1, String.valueOf(code), msg, response);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("DELETE请求失败: url={}, error={}", urlStr, e.getMessage(), e);
|
||||
return new FirewallResponse(false, "-1", "请求失败: " + e.getMessage());
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行DELETE请求(带请求体)
|
||||
*/
|
||||
private FirewallResponse doDelete(String urlStr, String username, String password, Map<String, Object> payload) {
|
||||
HttpURLConnection conn = null;
|
||||
try {
|
||||
URL url = new URL(urlStr);
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
setupConnection(conn, username, password, "DELETE");
|
||||
|
||||
// 发送请求体
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String jsonBody = mapper.writeValueAsString(payload);
|
||||
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
String response = readResponse(conn);
|
||||
|
||||
logger.info("DELETE请求响应: url={}, code={}, response={}", urlStr, responseCode, response);
|
||||
|
||||
JsonNode jsonNode = mapper.readTree(response);
|
||||
int code = jsonNode.has("code") ? jsonNode.get("code").asInt() : responseCode;
|
||||
String msg = jsonNode.has("msg") && !jsonNode.get("msg").isNull() ? jsonNode.get("msg").asText() : "";
|
||||
|
||||
return new FirewallResponse(code == 1, String.valueOf(code), msg, response);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("DELETE请求失败: url={}, error={}", urlStr, e.getMessage(), e);
|
||||
return new FirewallResponse(false, "-1", "请求失败: " + e.getMessage());
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置HTTP连接
|
||||
*/
|
||||
private void setupConnection(HttpURLConnection conn, String username, String password, String method)
|
||||
throws NoSuchAlgorithmException, KeyManagementException, ProtocolException{
|
||||
conn.setRequestMethod(method);
|
||||
conn.setConnectTimeout(10000);
|
||||
conn.setReadTimeout(30000);
|
||||
conn.setDoInput(true);
|
||||
conn.setDoOutput(true);
|
||||
|
||||
// 设置请求头
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setRequestProperty("Accept", "application/json");
|
||||
|
||||
// HTTP Basic Auth
|
||||
String auth = username + ":" + password;
|
||||
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
|
||||
conn.setRequestProperty("Authorization", "Basic " + encodedAuth);
|
||||
|
||||
// 信任所有证书(用于HTTPS)
|
||||
if (conn instanceof HttpsURLConnection) {
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
|
||||
}}, new java.security.SecureRandom());
|
||||
|
||||
((HttpsURLConnection) conn).setSSLSocketFactory(sslContext.getSocketFactory());
|
||||
((HttpsURLConnection) conn).setHostnameVerifier((hostname, session) -> true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取响应内容
|
||||
*/
|
||||
private String readResponse(HttpURLConnection conn) throws IOException {
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
conn.getResponseCode() >= 400 ? conn.getErrorStream() : conn.getInputStream(),
|
||||
StandardCharsets.UTF_8))) {
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
return response.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 防火墙响应结果类
|
||||
*/
|
||||
public static class FirewallResponse {
|
||||
private boolean success;
|
||||
private String code;
|
||||
private String message;
|
||||
private String rawResponse;
|
||||
|
||||
public FirewallResponse(boolean success, String code, String message) {
|
||||
this.success = success;
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public FirewallResponse(boolean success, String code, String message, String rawResponse) {
|
||||
this.success = success;
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.rawResponse = rawResponse;
|
||||
}
|
||||
|
||||
public boolean isSuccess() { return success; }
|
||||
public void setSuccess(boolean success) { this.success = success; }
|
||||
public String getCode() { return code; }
|
||||
public void setCode(String code) { this.code = code; }
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
public String getRawResponse() { return rawResponse; }
|
||||
public void setRawResponse(String rawResponse) { this.rawResponse = rawResponse; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FirewallResponse{" +
|
||||
"success=" + success +
|
||||
", code='" + code + '\'' +
|
||||
", message='" + message + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
package com.haobang.interlocking;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 探针联动API客户端
|
||||
* 用于调用syslog-consumer模块提供的REST API
|
||||
*/
|
||||
@Component
|
||||
public class InterlockingApiClient {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InterlockingApiClient.class);
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Value("${interlocking.api-key:a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6}")
|
||||
private String apiKey;
|
||||
|
||||
@Value("${interlocking.api.base-url:http://localhost:8089/xdrservice/interlocking}")
|
||||
private String baseUrl;
|
||||
|
||||
/**
|
||||
* 获取待执行的封禁指令
|
||||
* @param probeId 探针ID
|
||||
* @return 指令列表
|
||||
*/
|
||||
public List<Map<String, Object>> getPendingCommands(Long probeId) {
|
||||
String url = baseUrl + "/cmd/pending?probeId=" + probeId;
|
||||
try {
|
||||
String response = doGet(url);
|
||||
JsonNode jsonNode = objectMapper.readTree(response);
|
||||
if (jsonNode.has("code") && jsonNode.get("code").asInt() == 200) {
|
||||
JsonNode dataNode = jsonNode.get("data");
|
||||
List<Map<String, Object>> commands = new ArrayList<>();
|
||||
if (dataNode.isArray()) {
|
||||
for (JsonNode node : dataNode) {
|
||||
commands.add(objectMapper.convertValue(node, Map.class));
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
logger.warn("获取待执行指令失败: {}", response);
|
||||
return Collections.emptyList();
|
||||
} catch (Exception e) {
|
||||
logger.error("获取待执行指令异常: {}", e.getMessage(), e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指令状态为执行中
|
||||
* @param cmdId 指令ID
|
||||
* @return 是否成功
|
||||
*/
|
||||
public boolean updateStatusToExecuting(Long cmdId) {
|
||||
String url = baseUrl + "/cmd/" + cmdId + "/status/executing";
|
||||
try {
|
||||
String response = doPut(url, null);
|
||||
JsonNode jsonNode = objectMapper.readTree(response);
|
||||
return jsonNode.has("code") && jsonNode.get("code").asInt() == 200;
|
||||
} catch (Exception e) {
|
||||
logger.error("更新指令状态为执行中失败: cmdId={}, error={}", cmdId, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指令状态为执行完成
|
||||
* @param cmdId 指令ID
|
||||
* @return 是否成功
|
||||
*/
|
||||
public boolean updateStatusToCompleted(Long cmdId) {
|
||||
String url = baseUrl + "/cmd/" + cmdId + "/status/completed";
|
||||
try {
|
||||
String response = doPut(url, null);
|
||||
JsonNode jsonNode = objectMapper.readTree(response);
|
||||
return jsonNode.has("code") && jsonNode.get("code").asInt() == 200;
|
||||
} catch (Exception e) {
|
||||
logger.error("更新指令状态为执行完成失败: cmdId={}, error={}", cmdId, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指令状态为执行失败
|
||||
* @param cmdId 指令ID
|
||||
* @param errorMessage 错误信息
|
||||
* @return 是否成功
|
||||
*/
|
||||
public boolean updateStatusToFailed(Long cmdId, String errorMessage) {
|
||||
String url = baseUrl + "/cmd/" + cmdId + "/status/failed";
|
||||
try {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("errorMessage", errorMessage);
|
||||
String response = doPut(url, body);
|
||||
JsonNode jsonNode = objectMapper.readTree(response);
|
||||
return jsonNode.has("code") && jsonNode.get("code").asInt() == 200;
|
||||
} catch (Exception e) {
|
||||
logger.error("更新指令状态为执行失败失败: cmdId={}, error={}", cmdId, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入封禁记录
|
||||
* @param logs 封禁记录列表
|
||||
* @return 是否成功
|
||||
*/
|
||||
public boolean batchInsertLogs(List<Map<String, Object>> logs) {
|
||||
String url = baseUrl + "/log/batch";
|
||||
try {
|
||||
Map<String, Object> request = new HashMap<>();
|
||||
request.put("logs", logs);
|
||||
String response = doPost(url, request);
|
||||
JsonNode jsonNode = objectMapper.readTree(response);
|
||||
return jsonNode.has("code") && jsonNode.get("code").asInt() == 200;
|
||||
} catch (Exception e) {
|
||||
logger.error("批量插入封禁记录失败: error={}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行GET请求
|
||||
*/
|
||||
private String doGet(String url) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("X-API-KEY", apiKey);
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行PUT请求
|
||||
*/
|
||||
private String doPut(String url, Map<String, Object> body) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.set("X-API-KEY", apiKey);
|
||||
|
||||
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.PUT, entity, String.class);
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行POST请求
|
||||
*/
|
||||
private String doPost(String url, Map<String, Object> body) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.set("X-API-KEY", apiKey);
|
||||
|
||||
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
public String getApiKey() { return apiKey; }
|
||||
public void setApiKey(String apiKey) { this.apiKey = apiKey; }
|
||||
public String getBaseUrl() { return baseUrl; }
|
||||
public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; }
|
||||
}
|
||||
+412
@@ -0,0 +1,412 @@
|
||||
package com.haobang.interlocking;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.haobang.firewall.FirewallApiClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* 探针联动封禁服务
|
||||
* 核心业务逻辑:
|
||||
* 1. 从syslog-consumer获取待执行的封禁指令
|
||||
* 2. 解析封禁指令,生成逐条指令
|
||||
* 3. 调用防火墙API执行封禁
|
||||
* 4. 记录封禁结果到syslog-consumer
|
||||
* 5. 更新指令状态
|
||||
*/
|
||||
@Service
|
||||
public class InterlockingService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InterlockingService.class);
|
||||
|
||||
@Autowired
|
||||
private InterlockingApiClient apiClient;
|
||||
|
||||
@Autowired
|
||||
private FirewallApiClient firewallClient;
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
// 探针ID,从配置读取
|
||||
@Value("${app.service.device_collect_id:1}")
|
||||
private Integer probeId;
|
||||
|
||||
// 是否启用联动功能
|
||||
@Value("${interlocking.enabled:true}")
|
||||
private boolean interlockingEnabled;
|
||||
|
||||
// 执行锁,防止重复执行
|
||||
private final AtomicBoolean executing = new AtomicBoolean(false);
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
logger.info("探针联动封禁服务初始化完成,探针ID: {}, 启用状态: {}", probeId, interlockingEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务:检查并执行待处理的封禁指令
|
||||
* 每30秒执行一次
|
||||
*/
|
||||
@Scheduled(fixedDelay = 30000)
|
||||
public void processPendingCommands() {
|
||||
if (!interlockingEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 防止重复执行
|
||||
if (!executing.compareAndSet(false, true)) {
|
||||
logger.debug("上次执行尚未完成,跳过本次调度");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info("开始检查待执行的封禁指令...");
|
||||
|
||||
// 1. 获取待执行的封禁指令
|
||||
List<Map<String, Object>> pendingCommands = apiClient.getPendingCommands(probeId.longValue());
|
||||
|
||||
if (pendingCommands.isEmpty()) {
|
||||
logger.debug("没有待执行的封禁指令");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("获取到 {} 条待执行的封禁指令", pendingCommands.size());
|
||||
|
||||
// 2. 逐条处理指令
|
||||
for (Map<String, Object> cmd : pendingCommands) {
|
||||
try {
|
||||
processCommand(cmd);
|
||||
} catch (Exception e) {
|
||||
logger.error("处理封禁指令异常: cmdId={}, error={}", cmd.get("id"), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("检查待执行指令失败: {}", e.getMessage(), e);
|
||||
} finally {
|
||||
executing.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单条封禁指令
|
||||
* 指令数据结构(JSON字段名为驼峰格式):
|
||||
* - banIps: 封禁IP数组
|
||||
* - banType: 封禁类型(0:黑名单、1:白名单)
|
||||
* - banOperationType: 操作类型(0:新增、1:删除)
|
||||
* - banDuration: 封禁时长(秒)
|
||||
* - deviceInterlockingIp: 联动设备IP数组
|
||||
* - deviceInterlockingId: 联动设备ID数组
|
||||
*/
|
||||
private void processCommand(Map<String, Object> cmd) {
|
||||
Long cmdId = ((Number) cmd.get("id")).longValue();
|
||||
// JSON字段名使用驼峰格式
|
||||
List<String> banIps = parseStringArray(cmd.get("banIps"));
|
||||
String banType = (String) cmd.get("banType");
|
||||
Integer banOperationType = cmd.get("banOperationType") != null ?
|
||||
((Number) cmd.get("banOperationType")).intValue() : 0;
|
||||
Integer banDuration = cmd.get("banDuration") != null ?
|
||||
((Number) cmd.get("banDuration")).intValue() : -1;
|
||||
List<String> deviceIps = parseStringArray(cmd.get("deviceInterlockingIp"));
|
||||
|
||||
logger.info("开始处理封禁指令: cmdId={}, banType={}, operationType={}, ipCount={}",
|
||||
cmdId, banType, banOperationType, banIps.size());
|
||||
|
||||
try {
|
||||
// 3. 更新状态为执行中
|
||||
if (!apiClient.updateStatusToExecuting(cmdId)) {
|
||||
logger.warn("更新指令状态为执行中失败,跳过此指令: cmdId={}", cmdId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (banIps.isEmpty()) {
|
||||
logger.warn("封禁IP列表为空: cmdId={}", cmdId);
|
||||
apiClient.updateStatusToCompleted(cmdId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 根据设备列表执行封禁
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
List<Map<String, Object>> allResults = new ArrayList<>();
|
||||
|
||||
// 遍历每个联动设备执行封禁
|
||||
for (String deviceIp : deviceIps) {
|
||||
// 设置防火墙客户端的设备IP(这里简化处理,实际可能需要从配置获取)
|
||||
List<Map<String, Object>> results = executeBlockOperations(
|
||||
deviceIp, banType, banOperationType, banIps, banDuration, cmdId);
|
||||
allResults.addAll(results);
|
||||
|
||||
for (Map<String, Object> result : results) {
|
||||
// banResult: 1表示成功,0表示失败
|
||||
if ("1".equals(result.get("banResult"))) {
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 批量记录封禁结果
|
||||
for (Map<String, Object> result : allResults) {
|
||||
result.put("deviceInterlockingCmdId", cmdId);
|
||||
result.put("probeId", probeId);
|
||||
result.put("banMethod", "1"); // 自动化封禁
|
||||
}
|
||||
|
||||
boolean logSaved = apiClient.batchInsertLogs(allResults);
|
||||
if (!logSaved) {
|
||||
logger.warn("批量记录封禁结果失败: cmdId={}", cmdId);
|
||||
}
|
||||
|
||||
// 6. 更新指令状态为执行完成
|
||||
if (apiClient.updateStatusToCompleted(cmdId)) {
|
||||
logger.info("封禁指令执行完成: cmdId={}, 成功={}, 失败={}", cmdId, successCount, failCount);
|
||||
} else {
|
||||
logger.error("更新指令状态为执行完成失败: cmdId={}", cmdId);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("处理封禁指令异常: cmdId={}, error={}", cmdId, e.getMessage(), e);
|
||||
apiClient.updateStatusToFailed(cmdId, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析PostgreSQL数组格式
|
||||
*/
|
||||
private List<String> parseStringArray(Object obj) {
|
||||
List<String> result = new ArrayList<>();
|
||||
if (obj == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
if (obj instanceof List) {
|
||||
for (Object item : (List<?>) obj) {
|
||||
result.add(String.valueOf(item));
|
||||
}
|
||||
} else if (obj instanceof String) {
|
||||
String str = (String) obj;
|
||||
// 处理PostgreSQL数组格式 {a,b,c}
|
||||
if (str.startsWith("{") && str.endsWith("}")) {
|
||||
str = str.substring(1, str.length() - 1);
|
||||
for (String item : str.split(",")) {
|
||||
if (!item.isEmpty()) {
|
||||
result.add(item.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("解析数组失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行封禁操作
|
||||
* @param deviceIp 设备IP
|
||||
* @param banType 封禁类型(0:黑名单、1:白名单)
|
||||
* @param operationType 操作类型(0:新增、1:删除)
|
||||
* @param ipList IP列表
|
||||
* @param duration 封禁时长
|
||||
* @param cmdId 指令ID
|
||||
*/
|
||||
private List<Map<String, Object>> executeBlockOperations(
|
||||
String deviceIp, String banType, int operationType,
|
||||
List<String> ipList, int duration, Long cmdId) {
|
||||
|
||||
List<Map<String, Object>> results = new ArrayList<>();
|
||||
|
||||
// 确定操作类型
|
||||
String operationName;
|
||||
if ("0".equals(banType)) {
|
||||
// 黑名单
|
||||
operationName = operationType == 0 ? "add_blacklist" : "del_blacklist";
|
||||
} else {
|
||||
// 白名单
|
||||
operationName = operationType == 0 ? "add_whitelist" : "del_whitelist";
|
||||
}
|
||||
|
||||
for (String ip : ipList) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("banIp", ip);
|
||||
result.put("deviceInterlockingId", null); // 后续可关联
|
||||
result.put("deviceName", deviceIp);
|
||||
result.put("banResult", "0"); // 默认失败,0表示失败
|
||||
result.put("reqBody", "");
|
||||
result.put("respBody", "");
|
||||
|
||||
try {
|
||||
FirewallApiClient.FirewallResponse response;
|
||||
|
||||
switch (operationName) {
|
||||
case "add_blacklist":
|
||||
response = firewallClient.addToBlacklist(ip, duration, "联动封禁");
|
||||
break;
|
||||
case "del_blacklist":
|
||||
response = firewallClient.removeFromBlacklist(ip);
|
||||
break;
|
||||
case "add_whitelist":
|
||||
response = firewallClient.addToWhitelist(ip, "whitelist_" + ip, "联动封禁白名单");
|
||||
break;
|
||||
case "del_whitelist":
|
||||
response = firewallClient.removeFromWhitelist(ip);
|
||||
break;
|
||||
default:
|
||||
logger.warn("未知的指令类型: {}", operationName);
|
||||
result.put("respBody", "未知的指令类型: " + operationName);
|
||||
results.add(result);
|
||||
continue;
|
||||
}
|
||||
|
||||
// banResult: 1表示成功,0表示失败
|
||||
result.put("banResult", response.isSuccess() ? "1" : "0");
|
||||
result.put("respBody", response.getRawResponse());
|
||||
|
||||
// 构建请求body用于记录
|
||||
result.put("reqBody", buildRequestBody(operationName, ip, duration));
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("执行封禁操作异常: ip={}, operation={}, error={}", ip, operationName, e.getMessage());
|
||||
result.put("respBody", "执行异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
results.add(result);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建请求body用于记录
|
||||
*/
|
||||
private String buildRequestBody(String cmdType, String ip, int duration) {
|
||||
try {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
switch (cmdType) {
|
||||
case "add_blacklist":
|
||||
body.put("blist", ip);
|
||||
body.put("age", String.valueOf(duration));
|
||||
body.put("enable", "1");
|
||||
break;
|
||||
case "del_blacklist":
|
||||
body.put("blist", ip);
|
||||
break;
|
||||
case "add_whitelist":
|
||||
body.put("enable", "1");
|
||||
body.put("name", "whitelist_" + ip);
|
||||
List<Map<String, String>> addr = new ArrayList<>();
|
||||
Map<String, String> addrItem = new HashMap<>();
|
||||
addrItem.put("address", ip);
|
||||
addr.add(addrItem);
|
||||
body.put("addr", addr);
|
||||
break;
|
||||
case "del_whitelist":
|
||||
body.put("name", ip);
|
||||
break;
|
||||
}
|
||||
return objectMapper.writeValueAsString(body);
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发封禁
|
||||
*/
|
||||
public Map<String, Object> manualBlock(String ip, String cmdType, int age, String reason) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
FirewallApiClient.FirewallResponse response;
|
||||
|
||||
switch (cmdType) {
|
||||
case "add_blacklist":
|
||||
response = firewallClient.addToBlacklist(ip, age, reason);
|
||||
break;
|
||||
case "del_blacklist":
|
||||
response = firewallClient.removeFromBlacklist(ip);
|
||||
break;
|
||||
case "add_whitelist":
|
||||
response = firewallClient.addToWhitelist(ip, "manual_" + ip, reason);
|
||||
break;
|
||||
case "del_whitelist":
|
||||
response = firewallClient.removeFromWhitelist(ip);
|
||||
break;
|
||||
default:
|
||||
result.put("success", false);
|
||||
result.put("message", "未知的指令类型: " + cmdType);
|
||||
return result;
|
||||
}
|
||||
|
||||
result.put("success", response.isSuccess());
|
||||
result.put("code", response.getCode());
|
||||
result.put("message", response.getMessage());
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("手动封禁异常: ip={}, cmdType={}, error={}", ip, cmdType, e.getMessage());
|
||||
result.put("success", false);
|
||||
result.put("message", "执行异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量手动封禁
|
||||
*/
|
||||
public Map<String, Object> batchManualBlock(List<String> ips, String cmdType, int age, String reason) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
List<Map<String, String>> ipList = new ArrayList<>();
|
||||
|
||||
for (String ip : ips) {
|
||||
Map<String, String> ipInfo = new HashMap<>();
|
||||
ipInfo.put("ip", ip);
|
||||
ipInfo.put("age", String.valueOf(age));
|
||||
ipInfo.put("reason", reason);
|
||||
ipList.add(ipInfo);
|
||||
}
|
||||
|
||||
try {
|
||||
FirewallApiClient.FirewallResponse response;
|
||||
|
||||
if ("add_blacklist".equals(cmdType)) {
|
||||
response = firewallClient.batchAddToBlacklist(ipList);
|
||||
} else if ("del_blacklist".equals(cmdType)) {
|
||||
response = firewallClient.batchRemoveFromBlacklist(ips);
|
||||
} else {
|
||||
result.put("success", false);
|
||||
result.put("message", "批量操作暂不支持此类型: " + cmdType);
|
||||
return result;
|
||||
}
|
||||
|
||||
result.put("success", response.isSuccess());
|
||||
result.put("code", response.getCode());
|
||||
result.put("message", response.getMessage());
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("批量手动封禁异常: cmdType={}, error={}", cmdType, e.getMessage());
|
||||
result.put("success", false);
|
||||
result.put("message", "执行异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Integer getProbeId() { return probeId; }
|
||||
public void setProbeId(Integer probeId) { this.probeId = probeId; }
|
||||
public boolean isInterlockingEnabled() { return interlockingEnabled; }
|
||||
public void setInterlockingEnabled(boolean interlockingEnabled) { this.interlockingEnabled = interlockingEnabled; }
|
||||
}
|
||||
Reference in New Issue
Block a user