🔨 优化告警引擎.
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.dromara.visor.module.monitor.convert;
|
package org.dromara.visor.module.monitor.convert;
|
||||||
|
|
||||||
|
import org.dromara.visor.common.mapstruct.JsonConversion;
|
||||||
import org.dromara.visor.module.monitor.entity.domain.AlarmEventDO;
|
import org.dromara.visor.module.monitor.entity.domain.AlarmEventDO;
|
||||||
import org.dromara.visor.module.monitor.entity.dto.AlarmEventTriggerDTO;
|
import org.dromara.visor.module.monitor.entity.dto.AlarmEventTriggerDTO;
|
||||||
import org.dromara.visor.module.monitor.entity.dto.AlarmPolicyAlarmCountDTO;
|
import org.dromara.visor.module.monitor.entity.dto.AlarmPolicyAlarmCountDTO;
|
||||||
@@ -40,7 +41,7 @@ import java.util.List;
|
|||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
* @since 2025-9-17 21:31
|
* @since 2025-9-17 21:31
|
||||||
*/
|
*/
|
||||||
@Mapper
|
@Mapper(uses = JsonConversion.class)
|
||||||
public interface AlarmEventConvert {
|
public interface AlarmEventConvert {
|
||||||
|
|
||||||
AlarmEventConvert MAPPER = Mappers.getMapper(AlarmEventConvert.class);
|
AlarmEventConvert MAPPER = Mappers.getMapper(AlarmEventConvert.class);
|
||||||
|
|||||||
@@ -57,17 +57,17 @@ public class AlarmEventDO extends BaseDO {
|
|||||||
@TableField("agent_key")
|
@TableField("agent_key")
|
||||||
private String agentKey;
|
private String agentKey;
|
||||||
|
|
||||||
@Schema(description = "主机id")
|
@Schema(description = "事件来源")
|
||||||
@TableField("host_id")
|
@TableField("source_type")
|
||||||
private Long hostId;
|
private String sourceType;
|
||||||
|
|
||||||
@Schema(description = "主机名称")
|
@Schema(description = "事件来源id")
|
||||||
@TableField("host_name")
|
@TableField("source_id")
|
||||||
private String hostName;
|
private Long sourceId;
|
||||||
|
|
||||||
@Schema(description = "主机地址")
|
@Schema(description = "事件来源id")
|
||||||
@TableField("host_address")
|
@TableField("source_info")
|
||||||
private String hostAddress;
|
private String sourceInfo;
|
||||||
|
|
||||||
@Schema(description = "策略id")
|
@Schema(description = "策略id")
|
||||||
@TableField("policy_id")
|
@TableField("policy_id")
|
||||||
|
|||||||
@@ -56,14 +56,14 @@ public class AlarmEventTriggerDTO extends BaseDO {
|
|||||||
@Schema(description = "agentKey")
|
@Schema(description = "agentKey")
|
||||||
private String agentKey;
|
private String agentKey;
|
||||||
|
|
||||||
@Schema(description = "主机id")
|
@Schema(description = "事件来源")
|
||||||
private Long hostId;
|
private String sourceType;
|
||||||
|
|
||||||
@Schema(description = "主机名称")
|
@Schema(description = "事件来源id")
|
||||||
private String hostName;
|
private Long sourceId;
|
||||||
|
|
||||||
@Schema(description = "主机地址")
|
@Schema(description = "事件来源id")
|
||||||
private String hostAddress;
|
private String sourceInfo;
|
||||||
|
|
||||||
@Schema(description = "策略id")
|
@Schema(description = "策略id")
|
||||||
private Long policyId;
|
private Long policyId;
|
||||||
|
|||||||
@@ -48,13 +48,16 @@ public class AlarmEventQueryRequest extends BaseQueryRequest {
|
|||||||
@Schema(description = "id")
|
@Schema(description = "id")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(description = "主机名称")
|
|
||||||
private Long hostId;
|
|
||||||
|
|
||||||
@Size(max = 32)
|
@Size(max = 32)
|
||||||
@Schema(description = "agentKey")
|
@Schema(description = "agentKey")
|
||||||
private String agentKey;
|
private String agentKey;
|
||||||
|
|
||||||
|
@Schema(description = "事件来源")
|
||||||
|
private String sourceType;
|
||||||
|
|
||||||
|
@Schema(description = "事件来源id")
|
||||||
|
private Long sourceId;
|
||||||
|
|
||||||
@Schema(description = "策略id")
|
@Schema(description = "策略id")
|
||||||
private Long policyId;
|
private Long policyId;
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.dromara.visor.module.monitor.entity.vo;
|
package org.dromara.visor.module.monitor.entity.vo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
@@ -51,14 +52,14 @@ public class AlarmEventVO implements Serializable {
|
|||||||
@Schema(description = "id")
|
@Schema(description = "id")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(description = "主机名称")
|
@Schema(description = "事件来源")
|
||||||
private Long hostId;
|
private String sourceType;
|
||||||
|
|
||||||
@Schema(description = "主机名称")
|
@Schema(description = "事件来源id")
|
||||||
private String hostName;
|
private Long sourceId;
|
||||||
|
|
||||||
@Schema(description = "主机地址")
|
@Schema(description = "事件来源id")
|
||||||
private String hostAddress;
|
private JSONObject sourceInfo;
|
||||||
|
|
||||||
@Schema(description = "agentKey")
|
@Schema(description = "agentKey")
|
||||||
private String agentKey;
|
private String agentKey;
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||||
|
*
|
||||||
|
* https://visor.dromara.org
|
||||||
|
* https://visor.dromara.org.cn
|
||||||
|
* https://visor.orionsec.cn
|
||||||
|
*
|
||||||
|
* Members:
|
||||||
|
* Jiahang Li - ljh1553488six@139.com - author
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.dromara.visor.module.monitor.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警事件来源
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2025/10/13 22:03
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum AlarmEventSourceTypeEnum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主机告警
|
||||||
|
*/
|
||||||
|
HOST,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拨测告警
|
||||||
|
*/
|
||||||
|
UPTIME,
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
public static AlarmEventSourceTypeEnum of(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (AlarmEventSourceTypeEnum item : values()) {
|
||||||
|
if (item.name().equals(value)) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -491,38 +491,41 @@ public abstract class BaseAlarmEngine implements IAlarmEngine {
|
|||||||
// 构建参数
|
// 构建参数
|
||||||
List<Map<String, Object>> paramsList = new ArrayList<>();
|
List<Map<String, Object>> paramsList = new ArrayList<>();
|
||||||
for (AlarmEventTriggerDTO event : alarmEvents) {
|
for (AlarmEventTriggerDTO event : alarmEvents) {
|
||||||
MonitorMetricsContextDTO metrics = monitorMetricsContext.getMonitorMetrics(event.getMetricsId());
|
try {
|
||||||
MetricsUnitEnum unit = MetricsUnitEnum.of(metrics.getUnit());
|
MonitorMetricsContextDTO metrics = monitorMetricsContext.getMonitorMetrics(event.getMetricsId());
|
||||||
AlarmLevelEnum level = AlarmLevelEnum.of(event.getAlarmLevel());
|
MetricsUnitEnum unit = MetricsUnitEnum.of(metrics.getUnit());
|
||||||
AlarmTriggerConditionEnum triggerCondition = AlarmTriggerConditionEnum.of(event.getTriggerCondition());
|
AlarmLevelEnum level = AlarmLevelEnum.of(event.getAlarmLevel());
|
||||||
|
AlarmTriggerConditionEnum triggerCondition = AlarmTriggerConditionEnum.of(event.getTriggerCondition());
|
||||||
|
|
||||||
// 告警事件参数
|
// 告警事件参数
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.put("id", event.getId());
|
params.put("id", event.getId());
|
||||||
params.put("relKey", event.getId());
|
params.put("relKey", event.getId());
|
||||||
params.put("policyId", policy.getId());
|
params.put("policyId", policy.getId());
|
||||||
params.put("policyName", policy.getName());
|
params.put("policyName", policy.getName());
|
||||||
params.put("ruleId", event.getPolicyRuleId());
|
params.put("ruleId", event.getPolicyRuleId());
|
||||||
params.put("hostId", event.getHostId());
|
params.put("metrics", metrics.getMeasurement() + "." + metrics.getValue());
|
||||||
params.put("hostName", event.getHostName());
|
params.put("metricsId", metrics.getId());
|
||||||
params.put("hostAddress", event.getHostAddress());
|
params.put("metricsName", metrics.getName());
|
||||||
params.put("metrics", metrics.getMeasurement() + "." + metrics.getValue());
|
params.put("metricsField", metrics.getValue());
|
||||||
params.put("metricsId", metrics.getId());
|
params.put("metricsMeasurement", metrics.getMeasurement());
|
||||||
params.put("metricsName", metrics.getName());
|
params.put("tags", event.getAlarmTags());
|
||||||
params.put("metricsField", metrics.getValue());
|
params.put("level", level.name());
|
||||||
params.put("metricsMeasurement", metrics.getMeasurement());
|
params.put("levelLabel", level.getLabel());
|
||||||
params.put("tags", event.getAlarmTags());
|
params.put("levelSeverity", level.getSeverity());
|
||||||
params.put("level", level.name());
|
params.put("levelColor", level.getColor());
|
||||||
params.put("levelLabel", level.getLabel());
|
params.put("consecutiveCount", event.getConsecutiveCount());
|
||||||
params.put("levelSeverity", level.getSeverity());
|
params.put("triggerCondition", triggerCondition.getCondition());
|
||||||
params.put("levelColor", level.getColor());
|
params.put("alarmInfo", event.getAlarmInfo());
|
||||||
params.put("consecutiveCount", event.getConsecutiveCount());
|
params.put("alarmValue", unit.format(event.getAlarmValue(), new MetricsUnitEnum.FormatOptions(2, metrics.getSuffix())));
|
||||||
params.put("triggerCondition", triggerCondition.getCondition());
|
params.put("alarmThreshold", unit.format(event.getAlarmThreshold(), new MetricsUnitEnum.FormatOptions(4, metrics.getSuffix())));
|
||||||
params.put("alarmInfo", event.getAlarmInfo());
|
params.put("alarmTime", Dates.format(event.getCreateTime()));
|
||||||
params.put("alarmValue", unit.format(event.getAlarmValue(), new MetricsUnitEnum.FormatOptions(2, metrics.getSuffix())));
|
// 设置额外告警推送参数
|
||||||
params.put("alarmThreshold", unit.format(event.getAlarmThreshold(), new MetricsUnitEnum.FormatOptions(4, metrics.getSuffix())));
|
this.setExtraAlarmPushParams(params, event);
|
||||||
params.put("alarmTime", Dates.format(event.getCreateTime()));
|
paramsList.add(params);
|
||||||
paramsList.add(params);
|
} catch (Exception e) {
|
||||||
|
log.info("AlarmEngine-setAlarmParams error", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 推送消息
|
// 推送消息
|
||||||
for (Map<String, Object> params : paramsList) {
|
for (Map<String, Object> params : paramsList) {
|
||||||
@@ -532,4 +535,12 @@ public abstract class BaseAlarmEngine implements IAlarmEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置告警推送参数
|
||||||
|
*
|
||||||
|
* @param params params
|
||||||
|
* @param event event
|
||||||
|
*/
|
||||||
|
protected abstract void setExtraAlarmPushParams(Map<String, Object> params, AlarmEventTriggerDTO event);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,12 @@ import org.dromara.visor.module.asset.entity.dto.host.HostBaseDTO;
|
|||||||
import org.dromara.visor.module.monitor.convert.AlarmEventConvert;
|
import org.dromara.visor.module.monitor.convert.AlarmEventConvert;
|
||||||
import org.dromara.visor.module.monitor.entity.domain.AlarmEventDO;
|
import org.dromara.visor.module.monitor.entity.domain.AlarmEventDO;
|
||||||
import org.dromara.visor.module.monitor.entity.dto.*;
|
import org.dromara.visor.module.monitor.entity.dto.*;
|
||||||
|
import org.dromara.visor.module.monitor.enums.AlarmEventSourceTypeEnum;
|
||||||
import org.dromara.visor.module.monitor.enums.AlarmHandleStatusEnum;
|
import org.dromara.visor.module.monitor.enums.AlarmHandleStatusEnum;
|
||||||
import org.dromara.visor.module.monitor.enums.AlarmSwitchEnum;
|
import org.dromara.visor.module.monitor.enums.AlarmSwitchEnum;
|
||||||
import org.dromara.visor.module.monitor.enums.MetricsUnitEnum;
|
import org.dromara.visor.module.monitor.enums.MetricsUnitEnum;
|
||||||
import org.dromara.visor.module.monitor.handler.alarm.model.AlarmEngineRule;
|
import org.dromara.visor.module.monitor.handler.alarm.model.AlarmEngineRule;
|
||||||
|
import org.dromara.visor.module.monitor.handler.alarm.model.HostAlarmSourceInfo;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@@ -98,9 +100,14 @@ public class MetricsAlarmEngine extends BaseAlarmEngine {
|
|||||||
Map<String, String> tags = agentMetrics.getTags();
|
Map<String, String> tags = agentMetrics.getTags();
|
||||||
AlarmEventDO alarmEvent = AlarmEventDO.builder()
|
AlarmEventDO alarmEvent = AlarmEventDO.builder()
|
||||||
.agentKey(agentKey)
|
.agentKey(agentKey)
|
||||||
.hostId(host.getId())
|
.sourceType(AlarmEventSourceTypeEnum.HOST.name())
|
||||||
.hostName(host.getName())
|
.sourceId(host.getId())
|
||||||
.hostAddress(host.getAddress())
|
.sourceInfo(HostAlarmSourceInfo.builder()
|
||||||
|
.name(host.getName())
|
||||||
|
.code(host.getCode())
|
||||||
|
.address(host.getAddress())
|
||||||
|
.build()
|
||||||
|
.toJsonString())
|
||||||
.policyId(rule.getPolicyId())
|
.policyId(rule.getPolicyId())
|
||||||
.policyRuleId(rule.getId())
|
.policyRuleId(rule.getId())
|
||||||
.metricsId(rule.getMetricsId())
|
.metricsId(rule.getMetricsId())
|
||||||
@@ -126,4 +133,13 @@ public class MetricsAlarmEngine extends BaseAlarmEngine {
|
|||||||
return AlarmEventConvert.MAPPER.toTrigger(alarmEvent);
|
return AlarmEventConvert.MAPPER.toTrigger(alarmEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setExtraAlarmPushParams(Map<String, Object> params, AlarmEventTriggerDTO event) {
|
||||||
|
HostAlarmSourceInfo sourceInfo = JSON.parseObject(event.getAlarmInfo(), HostAlarmSourceInfo.class);
|
||||||
|
params.put("hostId", event.getSourceId());
|
||||||
|
params.put("hostName", sourceInfo.getName());
|
||||||
|
params.put("hostCode", sourceInfo.getCode());
|
||||||
|
params.put("hostAddress", sourceInfo.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||||
|
*
|
||||||
|
* https://visor.dromara.org
|
||||||
|
* https://visor.dromara.org.cn
|
||||||
|
* https://visor.orionsec.cn
|
||||||
|
*
|
||||||
|
* Members:
|
||||||
|
* Jiahang Li - ljh1553488six@139.com - author
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.dromara.visor.module.monitor.handler.alarm.model;
|
||||||
|
|
||||||
|
import cn.orionsec.kit.lang.able.IJsonObject;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主机告警源信息
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2025/10/13 22:09
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Schema(name = "HostAlarmSourceInfo", description = "主机告警源信息")
|
||||||
|
public class HostAlarmSourceInfo implements IJsonObject {
|
||||||
|
|
||||||
|
@Schema(description = "主机名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "主机编码")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@Schema(description = "主机地址")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -223,7 +223,8 @@ public class AlarmEventServiceImpl implements AlarmEventService {
|
|||||||
public LambdaQueryWrapper<AlarmEventDO> buildQueryWrapper(AlarmEventQueryRequest request) {
|
public LambdaQueryWrapper<AlarmEventDO> buildQueryWrapper(AlarmEventQueryRequest request) {
|
||||||
return alarmEventDAO.wrapper()
|
return alarmEventDAO.wrapper()
|
||||||
.eq(AlarmEventDO::getId, request.getId())
|
.eq(AlarmEventDO::getId, request.getId())
|
||||||
.eq(AlarmEventDO::getHostId, request.getHostId())
|
.eq(AlarmEventDO::getSourceType, request.getSourceType())
|
||||||
|
.eq(AlarmEventDO::getSourceId, request.getSourceId())
|
||||||
.eq(AlarmEventDO::getAgentKey, request.getAgentKey())
|
.eq(AlarmEventDO::getAgentKey, request.getAgentKey())
|
||||||
.eq(AlarmEventDO::getPolicyId, request.getPolicyId())
|
.eq(AlarmEventDO::getPolicyId, request.getPolicyId())
|
||||||
.eq(AlarmEventDO::getMetricsId, request.getMetricsId())
|
.eq(AlarmEventDO::getMetricsId, request.getMetricsId())
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
<!-- 通用查询映射结果 -->
|
<!-- 通用查询映射结果 -->
|
||||||
<resultMap id="BaseResultMap" type="org.dromara.visor.module.monitor.entity.domain.AlarmEventDO">
|
<resultMap id="BaseResultMap" type="org.dromara.visor.module.monitor.entity.domain.AlarmEventDO">
|
||||||
<id column="id" property="id"/>
|
<id column="id" property="id"/>
|
||||||
<result column="host_id" property="hostId"/>
|
<result column="source_type" property="sourceType"/>
|
||||||
<result column="host_name" property="hostName"/>
|
<result column="source_id" property="sourceId"/>
|
||||||
<result column="host_address" property="hostAddress"/>
|
<result column="source_info" property="sourceInfo"/>
|
||||||
<result column="agent_key" property="agentKey"/>
|
<result column="agent_key" property="agentKey"/>
|
||||||
<result column="policy_id" property="policyId"/>
|
<result column="policy_id" property="policyId"/>
|
||||||
<result column="policy_rule_id" property="policyRuleId"/>
|
<result column="policy_rule_id" property="policyRuleId"/>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
<!-- 通用查询结果列 -->
|
<!-- 通用查询结果列 -->
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, host_id, host_name, host_address, agent_key, policy_id, policy_rule_id, metrics_id, metrics_measurement, alarm_tags, alarm_value, alarm_threshold, alarm_info, alarm_level, trigger_condition, consecutive_count, false_alarm, handle_status, handle_time, handle_remark, handle_user_id, handle_username, create_time, update_time, creator, updater, deleted
|
id, event_source, source_id, source_info, agent_key, policy_id, policy_rule_id, metrics_id, metrics_measurement, alarm_tags, alarm_value, alarm_threshold, alarm_info, alarm_level, trigger_condition, consecutive_count, false_alarm, handle_status, handle_time, handle_remark, handle_user_id, handle_username, create_time, update_time, creator, updater, deleted
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="selectPolicyEventCount" resultMap="CountResultMap">
|
<select id="selectPolicyEventCount" resultMap="CountResultMap">
|
||||||
|
|||||||
Reference in New Issue
Block a user