This is an automated email from the ASF dual-hosted git repository.

liuhongyu pushed a commit to branch feat/refactor_monitor
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git

commit a56aa09ed65df6adb49a90bb31a72cc40c2273fe
Author: liuhy <[email protected]>
AuthorDate: Thu Dec 4 16:52:12 2025 +0800

    [add] Add parameter validators and their corresponding tests
---
 .../component/validator/ParamValidator.java        |  44 +++
 .../component/validator/ParamValidatorManager.java |  49 ++++
 .../validator/impl/ArrayParamValidator.java        |  46 +++
 .../validator/impl/BooleanParamValidator.java      |  43 +++
 .../validator/impl/HostParamValidatorAdapter.java  |  49 ++++
 .../validator/impl/JsonParamValidator.java         |  45 +++
 .../validator/impl/NumberParamValidator.java       |  53 ++++
 .../validator/impl/OptionParamValidator.java       |  54 ++++
 .../validator/impl/PasswordParamValidator.java     |  46 +++
 .../validator/impl/TextParamValidator.java         |  43 +++
 .../service/helper/MonitorImExportHelper.java      |  85 ++++++
 .../manager/service/impl/MonitorServiceImpl.java   | 311 +++++++--------------
 .../validator/ParamValidatorManagerTest.java       |  53 ++++
 .../validator/impl/ArrayParamValidatorTest.java    |  97 +++++++
 .../validator/impl/BooleanParamValidatorTest.java  |  66 +++++
 .../impl/HostParamValidatorAdapterTest.java        |  76 +++++
 .../validator/impl/HostParamValidatorTest.java     |  74 +++++
 .../validator/impl/JsonParamValidatorTest.java     |  47 ++++
 .../validator/impl/NumberParamValidatorTest.java   |  71 +++++
 .../validator/impl/OptionParamValidatorTest.java   |  62 ++++
 .../validator/impl/PasswordParamValidatorTest.java |  56 ++++
 .../validator/impl/TextParamValidatorTest.java     |  49 ++++
 .../manager/service/MonitorServiceTest.java        | 114 +++++---
 .../service/helper/MonitorImExportHelperTest.java  |  81 ++++++
 24 files changed, 1462 insertions(+), 252 deletions(-)

diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/ParamValidator.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/ParamValidator.java
new file mode 100644
index 0000000000..b019c38115
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/ParamValidator.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.component.validator;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+
+/**
+ * Parameter validator interface
+ */
+public interface ParamValidator {
+
+    /**
+     * Check if the validator supports the given parameter type
+     * 
+     * @param type parameter type
+     * @return true if supported
+     */
+    boolean support(String type);
+
+    /**
+     * Validate the parameter
+     * 
+     * @param paramDefine parameter definition
+     * @param param       parameter actual value
+     * @throws IllegalArgumentException if validation fails
+     */
+    void validate(ParamDefine paramDefine, Param param) throws 
IllegalArgumentException;
+}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/ParamValidatorManager.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/ParamValidatorManager.java
new file mode 100644
index 0000000000..8943d7ff35
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/ParamValidatorManager.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.component.validator;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * Parameter validator manager
+ */
+@Component
+public class ParamValidatorManager {
+
+    private final List<ParamValidator> validators;
+
+    public ParamValidatorManager(List<ParamValidator> validators) {
+        this.validators = validators;
+    }
+
+    public void validate(ParamDefine paramDefine, Param param) {
+        for (ParamValidator validator : validators) {
+            if (validator.support(paramDefine.getType())) {
+                validator.validate(paramDefine, param);
+                return;
+            }
+        }
+        // If no validator found, maybe throw exception or ignore?
+        // Original code threw exception for default case.
+        throw new IllegalArgumentException("ParamDefine type " + 
paramDefine.getType() + " is invalid.");
+    }
+}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/ArrayParamValidator.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/ArrayParamValidator.java
new file mode 100644
index 0000000000..d215a508ff
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/ArrayParamValidator.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.apache.hertzbeat.manager.component.validator.ParamValidator;
+import org.springframework.stereotype.Component;
+
+/**
+ * Number parameter validator
+ */
+@Component
+public class ArrayParamValidator implements ParamValidator {
+    @Override
+    public boolean support(String type) {
+        return "array".equals(type);
+    }
+
+    @Override
+    public void validate(ParamDefine paramDefine, Param param) {
+        String[] arrays = param.getParamValue().split(",");
+        if (arrays.length == 0) {
+            throw new IllegalArgumentException("Param field" + 
paramDefine.getField() + " value "
+                    + param.getParamValue() + " is invalid arrays value");
+        }
+        if (param.getParamValue().startsWith("[") && 
param.getParamValue().endsWith("]")) {
+            param.setParamValue(param.getParamValue().substring(1, 
param.getParamValue().length() - 1));
+        }
+    }
+}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/BooleanParamValidator.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/BooleanParamValidator.java
new file mode 100644
index 0000000000..46f7ce484d
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/BooleanParamValidator.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.apache.hertzbeat.manager.component.validator.ParamValidator;
+import org.springframework.stereotype.Component;
+
+/**
+ * Number parameter validator
+ */
+@Component
+public class BooleanParamValidator implements ParamValidator {
+    @Override
+    public boolean support(String type) {
+        return "boolean".equals(type);
+    }
+
+    @Override
+    public void validate(ParamDefine paramDefine, Param param) {
+        String booleanValue = param.getParamValue();
+        if (!"true".equalsIgnoreCase(booleanValue) && 
!"false".equalsIgnoreCase(booleanValue)) {
+            throw new IllegalArgumentException("Params field " + 
paramDefine.getField() + " value "
+                    + booleanValue + " is invalid boolean value.");
+        }
+    }
+}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/HostParamValidatorAdapter.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/HostParamValidatorAdapter.java
new file mode 100644
index 0000000000..245d3dbeab
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/HostParamValidatorAdapter.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.apache.hertzbeat.manager.component.validator.ParamValidator;
+import org.springframework.stereotype.Component;
+
+/**
+ * Host parameter validator that delegates to the common HostParamValidator
+ */
+@Component
+public class HostParamValidatorAdapter implements ParamValidator {
+
+    private final org.apache.hertzbeat.common.support.valid.HostParamValidator 
hostValidator;
+
+    public HostParamValidatorAdapter() {
+        this.hostValidator = new 
org.apache.hertzbeat.common.support.valid.HostParamValidator();
+    }
+
+    @Override
+    public boolean support(String type) {
+        return "host".equals(type);
+    }
+
+    @Override
+    public void validate(ParamDefine paramDefine, Param param) {
+        if (!hostValidator.isValid(param.getParamValue(), null)) {
+            throw new IllegalArgumentException("Params field " + 
paramDefine.getField() + " value "
+                    + param.getParamValue() + " is invalid host value.");
+        }
+    }
+}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/JsonParamValidator.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/JsonParamValidator.java
new file mode 100644
index 0000000000..1a9b3ba8a9
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/JsonParamValidator.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.component.validator.impl;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.apache.hertzbeat.common.util.JsonUtil;
+import org.apache.hertzbeat.manager.component.validator.ParamValidator;
+import org.springframework.stereotype.Component;
+
+/**
+ * JSON parameter validator
+ */
+@Component
+public class JsonParamValidator implements ParamValidator {
+    @Override
+    public boolean support(String type) {
+        return "metrics-field".equals(type) || "key-value".equals(type);
+    }
+
+    @Override
+    public void validate(ParamDefine paramDefine, Param param) {
+        if (JsonUtil.fromJson(param.getParamValue(), new TypeReference<>() {
+        }) == null) {
+            throw new IllegalArgumentException("Params field " + 
paramDefine.getField() + " value "
+                    + param.getParamValue() + " is invalid key-value value");
+        }
+    }
+}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/NumberParamValidator.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/NumberParamValidator.java
new file mode 100644
index 0000000000..bfd99fdbf5
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/NumberParamValidator.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.constants.CommonConstants;
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.apache.hertzbeat.common.util.IntervalExpressionUtil;
+import org.apache.hertzbeat.manager.component.validator.ParamValidator;
+import org.springframework.stereotype.Component;
+
+/**
+ * Number parameter validator
+ */
+@Component
+public class NumberParamValidator implements ParamValidator {
+    @Override
+    public boolean support(String type) {
+        return "number".equals(type);
+    }
+
+    @Override
+    public void validate(ParamDefine paramDefine, Param param) {
+        Double doubleValue = 
org.apache.hertzbeat.common.util.CommonUtil.parseStrDouble(param.getParamValue());
+        if (doubleValue == null) {
+            throw new IllegalArgumentException("Params field " + 
paramDefine.getField() + " type "
+                    + paramDefine.getType() + " is invalid.");
+        }
+        if (paramDefine.getRange() != null) {
+            if (!IntervalExpressionUtil.validNumberIntervalExpress(doubleValue,
+                    paramDefine.getRange())) {
+                throw new IllegalArgumentException("Params field " + 
paramDefine.getField() + " type "
+                        + paramDefine.getType() + " over range " + 
paramDefine.getRange());
+            }
+        }
+        param.setType(CommonConstants.PARAM_TYPE_NUMBER);
+    }
+}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/OptionParamValidator.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/OptionParamValidator.java
new file mode 100644
index 0000000000..eb76955912
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/OptionParamValidator.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.apache.hertzbeat.manager.component.validator.ParamValidator;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * Option parameter validator for radio and checkbox types
+ */
+@Component
+public class OptionParamValidator implements ParamValidator {
+    @Override
+    public boolean support(String type) {
+        return "radio".equals(type) || "checkbox".equals(type);
+    }
+
+    @Override
+    public void validate(ParamDefine paramDefine, Param param) {
+        List<ParamDefine.Option> options = paramDefine.getOptions();
+        boolean invalid = true;
+        if (options != null) {
+            for (ParamDefine.Option option : options) {
+                if (param.getParamValue().equalsIgnoreCase(option.getValue())) 
{
+                    invalid = false;
+                    break;
+                }
+            }
+        }
+        if (invalid) {
+            throw new IllegalArgumentException("Params field " + 
paramDefine.getField() + " value "
+                    + param.getParamValue() + " is invalid option value");
+        }
+    }
+}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/PasswordParamValidator.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/PasswordParamValidator.java
new file mode 100644
index 0000000000..0c4849b23a
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/PasswordParamValidator.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.constants.CommonConstants;
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.apache.hertzbeat.common.util.AesUtil;
+import org.apache.hertzbeat.manager.component.validator.ParamValidator;
+import org.springframework.stereotype.Component;
+
+/**
+ * Password parameter validator
+ */
+@Component
+public class PasswordParamValidator implements ParamValidator {
+    @Override
+    public boolean support(String type) {
+        return "password".equals(type);
+    }
+
+    @Override
+    public void validate(ParamDefine paramDefine, Param param) {
+        String passwordValue = param.getParamValue();
+        if (!AesUtil.isCiphertext(passwordValue)) {
+            passwordValue = AesUtil.aesEncode(passwordValue);
+            param.setParamValue(passwordValue);
+        }
+        param.setType(CommonConstants.PARAM_TYPE_PASSWORD);
+    }
+}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/TextParamValidator.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/TextParamValidator.java
new file mode 100644
index 0000000000..1fb7b30776
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/validator/impl/TextParamValidator.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.apache.hertzbeat.manager.component.validator.ParamValidator;
+import org.springframework.stereotype.Component;
+
+/**
+ * Text parameter validator
+ */
+@Component
+public class TextParamValidator implements ParamValidator {
+    @Override
+    public boolean support(String type) {
+        return "text".equals(type) || "textarea".equals(type);
+    }
+
+    @Override
+    public void validate(ParamDefine paramDefine, Param param) {
+        Short limit = paramDefine.getLimit();
+        if (limit != null && param.getParamValue().length() > limit) {
+            throw new IllegalArgumentException("Params field " + 
paramDefine.getField() + " type "
+                    + paramDefine.getType() + " over limit " + limit);
+        }
+    }
+}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/helper/MonitorImExportHelper.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/helper/MonitorImExportHelper.java
new file mode 100644
index 0000000000..9585feb7b9
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/helper/MonitorImExportHelper.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.service.helper;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.hertzbeat.common.constants.ExportFileConstants;
+import org.apache.hertzbeat.common.constants.SignConstants;
+import org.apache.hertzbeat.common.util.FileUtil;
+import org.apache.hertzbeat.manager.config.ManagerSseManager;
+import org.apache.hertzbeat.manager.service.ImExportService;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper class for monitor import and export operations
+ */
+@Component
+@Slf4j
+public class MonitorImExportHelper {
+
+    private static final String CONTENT_VALUE = 
MediaType.APPLICATION_OCTET_STREAM_VALUE + SignConstants.SINGLE_MARK
+            + "charset=" + StandardCharsets.UTF_8;
+
+    private final Map<String, ImExportService> imExportServiceMap = new 
HashMap<>();
+    private final ManagerSseManager managerSseManager;
+
+    public MonitorImExportHelper(List<ImExportService> imExportServiceList, 
ManagerSseManager managerSseManager) {
+        imExportServiceList.forEach(it -> imExportServiceMap.put(it.type(), 
it));
+        this.managerSseManager = managerSseManager;
+    }
+
+    public void export(List<Long> ids, String type, HttpServletResponse res) 
throws Exception {
+        var imExportService = imExportServiceMap.get(type);
+        if (imExportService == null) {
+            throw new IllegalArgumentException("not support export type: " + 
type);
+        }
+        var fileName = imExportService.getFileName();
+        res.setHeader(HttpHeaders.CONTENT_DISPOSITION, CONTENT_VALUE);
+        res.setContentType(CONTENT_VALUE);
+        res.setHeader(HttpHeaders.CONTENT_DISPOSITION,
+                "attachment;filename=" + URLEncoder.encode(fileName, 
StandardCharsets.UTF_8));
+        res.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, 
HttpHeaders.CONTENT_DISPOSITION);
+        imExportService.exportConfig(res.getOutputStream(), ids);
+    }
+
+    public void importConfig(MultipartFile file) throws Exception {
+        var fileName = FileUtil.getFileName(file);
+        var type = FileUtil.getFileType(file);
+        try {
+            if (!imExportServiceMap.containsKey(type)) {
+                String errMsg = ExportFileConstants.FILE + " " + fileName + " 
is not supported.";
+                throw new RuntimeException(errMsg);
+            }
+            var imExportService = imExportServiceMap.get(type);
+            imExportService.importConfig(fileName, file.getInputStream());
+        } catch (Exception e) {
+            managerSseManager.broadcastImportTaskFail(fileName, 
e.getMessage());
+            throw e;
+        }
+    }
+}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/MonitorServiceImpl.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/MonitorServiceImpl.java
index 2cf3da9371..4e574159df 100644
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/MonitorServiceImpl.java
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/MonitorServiceImpl.java
@@ -17,7 +17,6 @@
 
 package org.apache.hertzbeat.manager.service.impl;
 
-import com.fasterxml.jackson.core.type.TypeReference;
 import com.google.common.collect.Sets;
 import com.google.common.primitives.Longs;
 import com.usthe.sureness.subject.SubjectSum;
@@ -29,8 +28,6 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.hertzbeat.alert.dao.AlertDefineBindDao;
 import org.apache.hertzbeat.collector.dispatch.DispatchConstants;
 import org.apache.hertzbeat.common.constants.CommonConstants;
-import org.apache.hertzbeat.common.constants.ExportFileConstants;
-import org.apache.hertzbeat.common.constants.NetworkConstants;
 import org.apache.hertzbeat.common.constants.SignConstants;
 import org.apache.hertzbeat.common.entity.grafana.GrafanaDashboard;
 import org.apache.hertzbeat.common.entity.job.Configmap;
@@ -45,15 +42,11 @@ import org.apache.hertzbeat.common.entity.manager.Param;
 import org.apache.hertzbeat.common.entity.manager.ParamDefine;
 import org.apache.hertzbeat.common.entity.message.CollectRep;
 import org.apache.hertzbeat.common.support.event.MonitorDeletedEvent;
-import org.apache.hertzbeat.common.util.AesUtil;
-import org.apache.hertzbeat.common.util.FileUtil;
-import org.apache.hertzbeat.common.util.IntervalExpressionUtil;
-import org.apache.hertzbeat.common.util.IpDomainUtil;
+
 import org.apache.hertzbeat.common.util.JexlCheckerUtil;
-import org.apache.hertzbeat.common.util.JsonUtil;
 import org.apache.hertzbeat.common.util.SnowFlakeIdGenerator;
 import org.apache.hertzbeat.grafana.service.DashboardService;
-import org.apache.hertzbeat.manager.config.ManagerSseManager;
+import org.apache.hertzbeat.manager.component.validator.ParamValidatorManager;
 import org.apache.hertzbeat.manager.dao.CollectorDao;
 import org.apache.hertzbeat.manager.dao.CollectorMonitorBindDao;
 import org.apache.hertzbeat.manager.dao.LabelDao;
@@ -61,14 +54,14 @@ import org.apache.hertzbeat.manager.dao.MonitorBindDao;
 import org.apache.hertzbeat.manager.dao.MonitorDao;
 import org.apache.hertzbeat.manager.dao.ParamDao;
 import org.apache.hertzbeat.manager.pojo.dto.AppCount;
-import org.apache.hertzbeat.manager.pojo.dto.MetricsInfo;
 import org.apache.hertzbeat.manager.pojo.dto.MonitorDto;
+import org.apache.hertzbeat.manager.pojo.dto.MetricsInfo;
 import org.apache.hertzbeat.manager.scheduler.CollectJobScheduling;
 import org.apache.hertzbeat.manager.service.AppService;
-import org.apache.hertzbeat.manager.service.ImExportService;
 import org.apache.hertzbeat.manager.service.LabelService;
 import org.apache.hertzbeat.manager.service.MetricsFavoriteService;
 import org.apache.hertzbeat.manager.service.MonitorService;
+import org.apache.hertzbeat.manager.service.helper.MonitorImExportHelper;
 import org.apache.hertzbeat.manager.support.exception.MonitorDatabaseException;
 import org.apache.hertzbeat.manager.support.exception.MonitorDetectException;
 import org.apache.hertzbeat.warehouse.service.WarehouseService;
@@ -79,16 +72,12 @@ import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Sort;
 import org.springframework.data.jpa.domain.Specification;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -113,8 +102,10 @@ public class MonitorServiceImpl implements MonitorService {
     private static final byte ALL_MONITOR_STATUS = 9;
     public static final String PARAM_FIELD_PORT = "port";
 
-    private static final String CONTENT_VALUE = 
MediaType.APPLICATION_OCTET_STREAM_VALUE + SignConstants.SINGLE_MARK + 
"charset=" + StandardCharsets.UTF_8;
-    private final Map<String, ImExportService> imExportServiceMap = new 
HashMap<>();
+    @Autowired
+    private ParamValidatorManager paramValidatorManager;
+    @Autowired
+    private MonitorImExportHelper monitorImExportHelper;
     @Autowired
     private AppService appService;
     @Autowired
@@ -138,18 +129,12 @@ public class MonitorServiceImpl implements MonitorService 
{
     @Autowired
     private DashboardService dashboardService;
     @Autowired
-    private ManagerSseManager managerSseManager;
-    @Autowired
     private LabelDao labelDao;
     @Autowired
     private LabelService labelService;
     @Autowired
     private MetricsFavoriteService metricsFavoriteService;
 
-    public MonitorServiceImpl(List<ImExportService> imExportServiceList) {
-        imExportServiceList.forEach(it -> imExportServiceMap.put(it.type(), 
it));
-    }
-
     @Override
     @Transactional(readOnly = true)
     public void detectMonitor(Monitor monitor, List<Param> params, String 
collector) throws MonitorDetectException {
@@ -162,7 +147,8 @@ public class MonitorServiceImpl implements MonitorService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void addMonitor(Monitor monitor, List<Param> params, String 
collector, GrafanaDashboard grafanaDashboard) throws RuntimeException {
+    public void addMonitor(Monitor monitor, List<Param> params, String 
collector, GrafanaDashboard grafanaDashboard)
+            throws RuntimeException {
         // Apply for monitor id
         long monitorId = SnowFlakeIdGenerator.generateId();
         Map<String, String> labels = monitor.getLabels();
@@ -177,7 +163,8 @@ public class MonitorServiceImpl implements MonitorService {
         }
 
         // Construct the collection task Job entity
-        boolean isStatic = 
CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape()) || 
!StringUtils.hasText(monitor.getScrape());
+        boolean isStatic = 
CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape())
+                || !StringUtils.hasText(monitor.getScrape());
         String app = isStatic ? monitor.getApp() : monitor.getScrape();
         Job appDefine = appService.getAppDefine(app);
         if (!isStatic) {
@@ -199,7 +186,8 @@ public class MonitorServiceImpl implements MonitorService {
                 .findFirst()
                 .orElse(null);
         String portWithMark = (Objects.isNull(portParam) || 
!StringUtils.hasText(portParam.getParamValue()))
-                ? "" : SignConstants.DOUBLE_MARK + portParam.getParamValue();
+                ? ""
+                : SignConstants.DOUBLE_MARK + portParam.getParamValue();
         if (Objects.nonNull(instance)) {
             instance = instance + portWithMark;
         }
@@ -215,11 +203,12 @@ public class MonitorServiceImpl implements MonitorService 
{
             return new Configmap(param.getField(), param.getParamValue(), 
param.getType());
         }).collect(Collectors.toList());
         appDefine.setConfigmap(configmaps);
-        long jobId = collector == null ? 
collectJobScheduling.addAsyncCollectJob(appDefine, null) :
-                collectJobScheduling.addAsyncCollectJob(appDefine, collector);
+        long jobId = collector == null ? 
collectJobScheduling.addAsyncCollectJob(appDefine, null)
+                : collectJobScheduling.addAsyncCollectJob(appDefine, 
collector);
         try {
             detectMonitor(monitor, params, collector);
-        } catch (Exception ignored) {}
+        } catch (Exception ignored) {
+        }
 
         try {
             if (collector != null) {
@@ -232,7 +221,8 @@ public class MonitorServiceImpl implements MonitorService {
             monitor.setId(monitorId);
             monitor.setJobId(jobId);
             // create grafana dashboard
-            if (monitor.getApp().equals(CommonConstants.PROMETHEUS) && 
grafanaDashboard != null && grafanaDashboard.isEnabled()) {
+            if (monitor.getApp().equals(CommonConstants.PROMETHEUS) && 
grafanaDashboard != null
+                    && grafanaDashboard.isEnabled()) {
                 
dashboardService.createOrUpdateDashboard(grafanaDashboard.getTemplate(), 
monitorId);
             }
             monitorDao.save(monitor);
@@ -246,16 +236,7 @@ public class MonitorServiceImpl implements MonitorService {
 
     @Override
     public void export(List<Long> ids, String type, HttpServletResponse res) 
throws Exception {
-        var imExportService = imExportServiceMap.get(type);
-        if (imExportService == null) {
-            throw new IllegalArgumentException("not support export type: " + 
type);
-        }
-        var fileName = imExportService.getFileName();
-        res.setHeader(HttpHeaders.CONTENT_DISPOSITION, CONTENT_VALUE);
-        res.setContentType(CONTENT_VALUE);
-        res.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" 
+ URLEncoder.encode(fileName, StandardCharsets.UTF_8));
-        res.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, 
HttpHeaders.CONTENT_DISPOSITION);
-        imExportService.exportConfig(res.getOutputStream(), ids);
+        monitorImExportHelper.export(ids, type, res);
     }
 
     @Override
@@ -265,32 +246,21 @@ public class MonitorServiceImpl implements MonitorService 
{
                 .stream()
                 .map(Monitor::getId)
                 .collect(Collectors.toList());
-        
+
         // Use the existing export method to export all monitors
         export(allMonitorIds, type, res);
     }
 
     @Override
     public void importConfig(MultipartFile file) throws Exception {
-        var fileName = FileUtil.getFileName(file);
-        var type = FileUtil.getFileType(file);
-        try {
-            if (!imExportServiceMap.containsKey(type)) {
-                String errMsg = ExportFileConstants.FILE + " " + fileName + " 
is not supported.";
-                throw new RuntimeException(errMsg);
-            }
-            var imExportService = imExportServiceMap.get(type);
-            imExportService.importConfig(fileName, file.getInputStream());
-        } catch (Exception e){
-            managerSseManager.broadcastImportTaskFail(fileName, 
e.getMessage());
-            throw e;
-        }
+        monitorImExportHelper.importConfig(file);
     }
 
     @Override
     @Transactional(readOnly = true)
     public void validate(MonitorDto monitorDto, Boolean isModify) throws 
IllegalArgumentException {
-        // The request monitoring parameter matches the monitoring parameter 
definition mapping check
+        // The request monitoring parameter matches the monitoring parameter 
definition
+        // mapping check
         Monitor monitor = monitorDto.getMonitor();
         // The Service Discovery host field may be null
         monitor.setInstance(StringUtils.hasText(monitor.getInstance()) ? 
monitor.getInstance().trim() : null);
@@ -303,7 +273,7 @@ public class MonitorServiceImpl implements MonitorService {
                     param.setParamValue(value);
                 })
                 .collect(Collectors.toMap(Param::getField, param -> param));
-        // Check name uniqueness and can not equal app type    
+        // Check name uniqueness and can not equal app type
         if (isModify != null) {
             Optional<Job> defineOptional = 
appService.getAppDefineOption(monitor.getName());
             if (defineOptional.isPresent()) {
@@ -333,7 +303,8 @@ public class MonitorServiceImpl implements MonitorService {
         // Parameter definition structure verification
         List<ParamDefine> paramDefines = 
appService.getAppParamDefines(monitorDto.getMonitor().getApp());
         if (!CollectionUtils.isEmpty(paramDefines)) {
-            boolean isStatic = 
CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape()) || 
!StringUtils.hasText(monitor.getScrape());
+            boolean isStatic = 
CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape())
+                    || !StringUtils.hasText(monitor.getScrape());
             for (ParamDefine paramDefine : paramDefines) {
                 String field = paramDefine.getField();
                 Param param = paramMap.get(field);
@@ -345,123 +316,7 @@ public class MonitorServiceImpl implements MonitorService 
{
                     throw new IllegalArgumentException("Params field " + field 
+ " is required.");
                 }
                 if (param != null && 
StringUtils.hasText(param.getParamValue())) {
-                    switch (paramDefine.getType()) {
-                        case "number":
-                            double doubleValue;
-                            try {
-                                doubleValue = 
Double.parseDouble(param.getParamValue());
-                            } catch (Exception e) {
-                                throw new IllegalArgumentException("Params 
field " + field + " type "
-                                        + paramDefine.getType() + " is 
invalid.");
-                            }
-                            if (paramDefine.getRange() != null) {
-                                if 
(!IntervalExpressionUtil.validNumberIntervalExpress(doubleValue,
-                                        paramDefine.getRange())) {
-                                    throw new IllegalArgumentException("Params 
field " + field + " type "
-                                            + paramDefine.getType() + " over 
range " + paramDefine.getRange());
-                                }
-                            }
-                            param.setType(CommonConstants.PARAM_TYPE_NUMBER);
-                            break;
-                        case "textarea":
-                            Short textareaLimit = paramDefine.getLimit();
-                            if (textareaLimit != null && 
param.getParamValue().length() > textareaLimit) {
-                                throw new IllegalArgumentException("Params 
field " + field + " type "
-                                        + paramDefine.getType() + " over limit 
" + param.getParamValue());
-                            }
-                            break;
-                        case "text":
-                            Short textLimit = paramDefine.getLimit();
-                            if (textLimit != null && 
param.getParamValue().length() > textLimit) {
-                                throw new IllegalArgumentException("Params 
field " + field + " type "
-                                        + paramDefine.getType() + " over limit 
" + textLimit);
-                            }
-                            break;
-                        case "host":
-                            String hostValue = param.getParamValue();
-                            if 
(hostValue.toLowerCase().contains(NetworkConstants.HTTP_HEADER)) {
-                                hostValue = hostValue.replaceAll(PATTERN_HTTP, 
SignConstants.BLANK);
-                            }
-                            if 
(hostValue.toLowerCase().contains(NetworkConstants.HTTPS_HEADER)) {
-                                hostValue = hostValue.replace(PATTERN_HTTPS, 
SignConstants.BLANK);
-                            }
-                            if (!IpDomainUtil.validateIpDomain(hostValue)) {
-                                throw new IllegalArgumentException("Params 
field " + field + " value "
-                                        + hostValue + " is invalid host 
value.");
-                            }
-                            break;
-                        case "password":
-                            // The plaintext password needs to be encrypted 
for transmission and storage
-                            String passwordValue = param.getParamValue();
-                            if (!AesUtil.isCiphertext(passwordValue)) {
-                                passwordValue = 
AesUtil.aesEncode(passwordValue);
-                                param.setParamValue(passwordValue);
-                            }
-                            param.setType(CommonConstants.PARAM_TYPE_PASSWORD);
-                            break;
-                        case "boolean":
-                            // boolean check
-                            String booleanValue = param.getParamValue();
-                            if (!"true".equalsIgnoreCase(booleanValue) && 
!"false".equalsIgnoreCase(booleanValue)) {
-                                throw new IllegalArgumentException("Params 
field " + field + " value "
-                                        + booleanValue + " is invalid boolean 
value.");
-                            }
-                            break;
-                        case "radio":
-                            // radio single value check
-                            List<ParamDefine.Option> options = 
paramDefine.getOptions();
-                            boolean invalid = true;
-                            if (options != null) {
-                                for (ParamDefine.Option option : options) {
-                                    if 
(param.getParamValue().equalsIgnoreCase(option.getValue())) {
-                                        invalid = false;
-                                        break;
-                                    }
-                                }
-                            }
-                            if (invalid) {
-                                throw new IllegalArgumentException("Params 
field " + field + " value "
-                                        + param.getParamValue() + " is invalid 
option value");
-                            }
-                            break;
-                        case "checkbox":
-                            List<ParamDefine.Option> checkboxOptions = 
paramDefine.getOptions();
-                            boolean checkboxInvalid = true;
-                            if (checkboxOptions != null) {
-                                for (ParamDefine.Option option : 
checkboxOptions) {
-                                    if 
(param.getParamValue().equalsIgnoreCase(option.getValue())) {
-                                        checkboxInvalid = false;
-                                        break;
-                                    }
-                                }
-                            }
-                            if (checkboxInvalid) {
-                                throw new IllegalArgumentException("Params 
field " + field + " value "
-                                        + param.getParamValue() + " is invalid 
checkbox value");
-                            }
-                            break;
-                        case "metrics-field":
-                        case "key-value":
-                            if (JsonUtil.fromJson(param.getParamValue(), new 
TypeReference<>() {
-                            }) == null) {
-                                throw new IllegalArgumentException("Params 
field " + field + " value "
-                                        + param.getParamValue() + " is invalid 
key-value value");
-                            }
-                            break;
-                        case "array":
-                            String[] arrays = param.getParamValue().split(",");
-                            if (arrays.length == 0) {
-                                throw new IllegalArgumentException("Param 
field" + field + " value "
-                                        + param.getParamValue() + " is invalid 
arrays value");
-                            }
-                            if (param.getParamValue().startsWith("[") && 
param.getParamValue().endsWith("]")) {
-                                
param.setParamValue(param.getParamValue().substring(1, 
param.getParamValue().length() - 1));
-                            }
-                            break;
-                        // todo More parameter definitions and actual value 
format verification
-                        default:
-                            throw new IllegalArgumentException("ParamDefine 
type " + paramDefine.getType() + " is invalid.");
-                    }
+                    paramValidatorManager.validate(paramDefine, param);
                 }
             }
         }
@@ -485,7 +340,8 @@ public class MonitorServiceImpl implements MonitorService {
                     }
                     if 
(JexlCheckerUtil.verifyStartCharacter(field.getField())) {
                         throw new IllegalArgumentException(job.getApp() + " " 
+ metrics.getName() + " "
-                                + field.getField() + " illegal start 
character, please modify the template information.");
+                                + field.getField()
+                                + " illegal start character, please modify the 
template information.");
                     }
                     if (JexlCheckerUtil.verifySpaces(field.getField())) {
                         throw new IllegalArgumentException(job.getApp() + " " 
+ metrics.getName() + " "
@@ -498,7 +354,8 @@ public class MonitorServiceImpl implements MonitorService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void modifyMonitor(Monitor monitor, List<Param> params, String 
collector, GrafanaDashboard grafanaDashboard) throws RuntimeException {
+    public void modifyMonitor(Monitor monitor, List<Param> params, String 
collector, GrafanaDashboard grafanaDashboard)
+            throws RuntimeException {
         long monitorId = monitor.getId();
         // Check to determine whether the monitor corresponding to the monitor 
id exists
         Optional<Monitor> queryOption = monitorDao.findById(monitorId);
@@ -529,13 +386,15 @@ public class MonitorServiceImpl implements MonitorService 
{
                 .findFirst()
                 .orElse(null);
         String portWithMark = (Objects.isNull(portParam) || 
!StringUtils.hasText(portParam.getParamValue()))
-                ? "" : SignConstants.DOUBLE_MARK + portParam.getParamValue();
+                ? ""
+                : SignConstants.DOUBLE_MARK + portParam.getParamValue();
         if (Objects.nonNull(instance)) {
             instance = instance + portWithMark;
         }
         monitor.setInstance(instance);
 
-        boolean isStatic = 
CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape()) || 
!StringUtils.hasText(monitor.getScrape());
+        boolean isStatic = 
CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape())
+                || !StringUtils.hasText(monitor.getScrape());
         if (preMonitor.getStatus() != CommonConstants.MONITOR_PAUSED_CODE) {
             // Construct the collection task Job entity
             String app = isStatic ? monitor.getApp() : monitor.getScrape();
@@ -558,8 +417,9 @@ public class MonitorServiceImpl implements MonitorService {
             appDefine.setMetadata(metadata);
             appDefine.setLabels(monitor.getLabels());
             appDefine.setAnnotations(monitor.getAnnotations());
-            List<Configmap> configmaps = params.stream().map(param ->
-                    new Configmap(param.getField(), param.getParamValue(), 
param.getType())).collect(Collectors.toList());
+            List<Configmap> configmaps = params.stream()
+                    .map(param -> new Configmap(param.getField(), 
param.getParamValue(), param.getType()))
+                    .collect(Collectors.toList());
             appDefine.setConfigmap(configmaps);
             long newJobId;
             if (collector == null) {
@@ -572,7 +432,8 @@ public class MonitorServiceImpl implements MonitorService {
             // execute only in non paused status
             try {
                 detectMonitor(monitor, params, collector);
-            } catch (Exception ignored) {}
+            } catch (Exception ignored) {
+            }
         }
 
         // After the update is successfully released, refresh the database
@@ -584,7 +445,8 @@ public class MonitorServiceImpl implements MonitorService {
                         .build();
                 collectorMonitorBindDao.save(collectorMonitorBind);
             }
-            // force update gmtUpdate time, due the case: monitor not change, 
param change. we also think monitor change
+            // force update gmtUpdate time, due the case: monitor not change, 
param change.
+            // we also think monitor change
             monitor.setGmtUpdate(LocalDateTime.now());
             // update or open grafana dashboard
             if (monitor.getApp().equals(CommonConstants.PROMETHEUS) && 
grafanaDashboard != null) {
@@ -616,7 +478,8 @@ public class MonitorServiceImpl implements MonitorService {
         if (CollectionUtils.isEmpty(ids)) {
             return;
         }
-        Set<Long> subMonitorIds = 
monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId).collect(Collectors.toSet());
+        Set<Long> subMonitorIds = 
monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId)
+                .collect(Collectors.toSet());
         Set<Long> allMonitorIds = new HashSet<>(ids);
         allMonitorIds.addAll(subMonitorIds);
         List<Monitor> monitors = monitorDao.findMonitorsByIdIn(allMonitorIds);
@@ -656,24 +519,29 @@ public class MonitorServiceImpl implements MonitorService 
{
             List<Param> params = paramDao.findParamsByMonitorId(id);
             monitorDto.setParams(params);
             List<MetricsInfo> metricsInfos;
-            if 
(DispatchConstants.PROTOCOL_PROMETHEUS.equalsIgnoreCase(monitor.getApp()) || 
monitor.getType() == CommonConstants.MONITOR_TYPE_PUSH_AUTO_CREATE) {
+            if 
(DispatchConstants.PROTOCOL_PROMETHEUS.equalsIgnoreCase(monitor.getApp())
+                    || monitor.getType() == 
CommonConstants.MONITOR_TYPE_PUSH_AUTO_CREATE) {
                 List<CollectRep.MetricsData> metricsDataList = 
warehouseService.queryMonitorMetricsData(id);
                 metricsInfos = metricsDataList.stream()
-                        .map(t -> 
MetricsInfo.builder().name(t.getMetrics()).favorited(favoritedMetrics.contains(t.getMetrics())).build())
+                        .map(t -> MetricsInfo.builder().name(t.getMetrics())
+                                
.favorited(favoritedMetrics.contains(t.getMetrics())).build())
                         .collect(Collectors.toList());
                 
monitorDto.setGrafanaDashboard(dashboardService.getDashboardByMonitorId(id));
             } else {
-                boolean isStatic = 
CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape()) || 
!StringUtils.hasText(monitor.getScrape());
+                boolean isStatic = 
CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape())
+                        || !StringUtils.hasText(monitor.getScrape());
                 String type = isStatic ? monitor.getApp() : 
monitor.getScrape();
                 Job job = appService.getAppDefine(type);
                 metricsInfos = job.getMetrics().stream()
                         .filter(Metrics::isVisible)
-                        .map(t -> 
MetricsInfo.builder().name(t.getName()).favorited(favoritedMetrics.contains(t.getName())).build())
+                        .map(t -> MetricsInfo.builder().name(t.getName())
+                                
.favorited(favoritedMetrics.contains(t.getName())).build())
                         .collect(Collectors.toList());
             }
             monitorDto.setMetrics(metricsInfos);
             monitorDto.setMonitor(monitor);
-            Optional<CollectorMonitorBind> bindOptional = 
collectorMonitorBindDao.findCollectorMonitorBindByMonitorId(monitor.getId());
+            Optional<CollectorMonitorBind> bindOptional = 
collectorMonitorBindDao
+                    .findCollectorMonitorBindByMonitorId(monitor.getId());
             bindOptional.ifPresent(bind -> 
monitorDto.setCollector(bind.getCollector()));
             return monitorDto;
         } else {
@@ -682,7 +550,8 @@ public class MonitorServiceImpl implements MonitorService {
     }
 
     @Override
-    public Page<Monitor> getMonitors(List<Long> monitorIds, String app, String 
search, Byte status, String sort, String order, int pageIndex, int pageSize, 
String labels) {
+    public Page<Monitor> getMonitors(List<Long> monitorIds, String app, String 
search, Byte status, String sort,
+            String order, int pageIndex, int pageSize, String labels) {
         Specification<Monitor> specification = (root, query, criteriaBuilder) 
-> {
             List<Predicate> andList = new ArrayList<>();
             if (!CollectionUtils.isEmpty(monitorIds)) {
@@ -706,7 +575,8 @@ public class MonitorServiceImpl implements MonitorService {
             List<Predicate> orList = new ArrayList<>();
             if (StringUtils.hasText(search)) {
                 Predicate predicateHost = 
criteriaBuilder.like(root.get("host"), "%" + search + "%");
-                Predicate predicateName = 
criteriaBuilder.like(criteriaBuilder.lower(root.get("name")), "%" + 
search.toLowerCase() + "%");
+                Predicate predicateName = 
criteriaBuilder.like(criteriaBuilder.lower(root.get("name")),
+                        "%" + search.toLowerCase() + "%");
                 Long id = Longs.tryParse(search);
                 if (id != null) {
                     orList.add(criteriaBuilder.equal(root.get("id"), id));
@@ -754,12 +624,13 @@ public class MonitorServiceImpl implements MonitorService 
{
             return;
         }
         // Update monitoring status Delete corresponding monitoring periodic 
task
-        // The jobId is not deleted, and the jobId is reused again after the 
management is started.
-        Set<Long> subMonitorIds = 
monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId).collect(Collectors.toSet());
+        // The jobId is not deleted, and the jobId is reused again after the 
management
+        // is started.
+        Set<Long> subMonitorIds = 
monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId)
+                .collect(Collectors.toSet());
         ids.addAll(subMonitorIds);
         List<Monitor> managedMonitors = monitorDao.findMonitorsByIdIn(ids)
-                .stream().filter(monitor ->
-                        monitor.getStatus() != 
CommonConstants.MONITOR_PAUSED_CODE)
+                .stream().filter(monitor -> monitor.getStatus() != 
CommonConstants.MONITOR_PAUSED_CODE)
                 .peek(monitor -> 
monitor.setStatus(CommonConstants.MONITOR_PAUSED_CODE))
                 .collect(Collectors.toList());
         if (!CollectionUtils.isEmpty(managedMonitors)) {
@@ -773,11 +644,11 @@ public class MonitorServiceImpl implements MonitorService 
{
     @Override
     public void enableManageMonitors(Set<Long> ids) {
         // Update monitoring status Add corresponding monitoring periodic task
-        Set<Long> subMonitorIds = 
monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId).collect(Collectors.toSet());
+        Set<Long> subMonitorIds = 
monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId)
+                .collect(Collectors.toSet());
         ids.addAll(subMonitorIds);
         List<Monitor> unManagedMonitors = monitorDao.findMonitorsByIdIn(ids)
-                .stream().filter(monitor ->
-                        monitor.getStatus() == 
CommonConstants.MONITOR_PAUSED_CODE)
+                .stream().filter(monitor -> monitor.getStatus() == 
CommonConstants.MONITOR_PAUSED_CODE)
                 .peek(monitor -> 
monitor.setStatus(CommonConstants.MONITOR_UP_CODE))
                 .collect(Collectors.toList());
         if (unManagedMonitors.isEmpty()) {
@@ -787,7 +658,8 @@ public class MonitorServiceImpl implements MonitorService {
         for (Monitor monitor : unManagedMonitors) {
             // Construct the collection task Job entity
             List<Param> params = 
paramDao.findParamsByMonitorId(monitor.getId());
-            boolean isStatic = 
CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape()) || 
!StringUtils.hasText(monitor.getScrape());
+            boolean isStatic = 
CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape())
+                    || !StringUtils.hasText(monitor.getScrape());
             String app = isStatic ? monitor.getApp() : monitor.getScrape();
             Job appDefine = appService.getAppDefine(app);
             if (!isStatic) {
@@ -807,22 +679,24 @@ public class MonitorServiceImpl implements MonitorService 
{
             appDefine.setMetadata(metadata);
             appDefine.setLabels(monitor.getLabels());
             appDefine.setAnnotations(monitor.getAnnotations());
-            List<Configmap> configmaps = params.stream().map(param ->
-                    new Configmap(param.getField(), param.getParamValue(), 
param.getType())).collect(Collectors.toList());
+            List<Configmap> configmaps = params.stream()
+                    .map(param -> new Configmap(param.getField(), 
param.getParamValue(), param.getType()))
+                    .collect(Collectors.toList());
             List<ParamDefine> paramDefaultValue = 
appDefine.getParams().stream()
                     .filter(item -> 
StringUtils.hasText(item.getDefaultValue()))
                     .toList();
             paramDefaultValue.forEach(defaultVar -> {
                 if (configmaps.stream().noneMatch(item -> 
item.getKey().equals(defaultVar.getField()))) {
-                    Configmap configmap = new Configmap(defaultVar.getField(), 
defaultVar.getDefaultValue(), CommonConstants.TYPE_STRING);
+                    Configmap configmap = new Configmap(defaultVar.getField(), 
defaultVar.getDefaultValue(),
+                            CommonConstants.TYPE_STRING);
                     configmaps.add(configmap);
                 }
             });
             appDefine.setConfigmap(configmaps);
 
             // Issue collection tasks
-            Optional<CollectorMonitorBind> bindOptional =
-                    
collectorMonitorBindDao.findCollectorMonitorBindByMonitorId(monitor.getId());
+            Optional<CollectorMonitorBind> bindOptional = 
collectorMonitorBindDao
+                    .findCollectorMonitorBindByMonitorId(monitor.getId());
             String collector = 
bindOptional.map(CollectorMonitorBind::getCollector).orElse(null);
             long newJobId = collectJobScheduling.addAsyncCollectJob(appDefine, 
collector);
             monitor.setJobId(newJobId);
@@ -841,24 +715,26 @@ public class MonitorServiceImpl implements MonitorService 
{
         if (CollectionUtils.isEmpty(appCounts)) {
             return null;
         }
-        //Statistical category information, calculate the number of 
corresponding states for each monitor
+        // Statistical category information, calculate the number of 
corresponding
+        // states for each monitor
         Map<String, AppCount> appCountMap = new HashMap<>(appCounts.size());
         for (AppCount item : appCounts) {
             AppCount appCount = appCountMap.getOrDefault(item.getApp(), new 
AppCount());
             appCount.setApp(item.getApp());
             switch (item.getStatus()) {
                 case CommonConstants.MONITOR_UP_CODE ->
-                        appCount.setAvailableSize(appCount.getAvailableSize() 
+ item.getSize());
+                    appCount.setAvailableSize(appCount.getAvailableSize() + 
item.getSize());
                 case CommonConstants.MONITOR_DOWN_CODE ->
-                        
appCount.setUnAvailableSize(appCount.getUnAvailableSize() + item.getSize());
+                    appCount.setUnAvailableSize(appCount.getUnAvailableSize() 
+ item.getSize());
                 case CommonConstants.MONITOR_PAUSED_CODE ->
-                        appCount.setUnManageSize(appCount.getUnManageSize() + 
item.getSize());
+                    appCount.setUnManageSize(appCount.getUnManageSize() + 
item.getSize());
                 default -> {
                 }
             }
             appCountMap.put(item.getApp(), appCount);
         }
-        //Traverse the map obtained by statistics and convert it into a 
List<App Count> result set
+        // Traverse the map obtained by statistics and convert it into a 
List<App Count>
+        // result set
         return appCountMap.values().stream().map(item -> {
             item.setSize(item.getAvailableSize() + item.getUnManageSize() + 
item.getUnAvailableSize());
             try {
@@ -911,7 +787,8 @@ public class MonitorServiceImpl implements MonitorService {
                         .toList();
                 paramDefaultValue.forEach(defaultVar -> {
                     if (configmaps.stream().noneMatch(item -> 
item.getKey().equals(defaultVar.getField()))) {
-                        Configmap configmap = new 
Configmap(defaultVar.getField(), defaultVar.getDefaultValue(), (byte) 1);
+                        Configmap configmap = new 
Configmap(defaultVar.getField(), defaultVar.getDefaultValue(),
+                                (byte) 1);
                         configmaps.add(configmap);
                     }
                 });
@@ -927,7 +804,7 @@ public class MonitorServiceImpl implements MonitorService {
             }
         }
     }
-    
+
     @Override
     public Monitor getMonitor(Long monitorId) {
         return monitorDao.findById(monitorId).orElse(null);
@@ -978,7 +855,6 @@ public class MonitorServiceImpl implements MonitorService {
         addMonitor(newMonitor, newParams, null, null);
     }
 
-
     private void detectSdMonitor(Monitor monitor, List<Param> params, String 
collector) {
         Long monitorId = monitor.getId();
         if (monitorId == null || monitorId == 0) {
@@ -995,8 +871,9 @@ public class MonitorServiceImpl implements MonitorService {
         appDefine.setMetadata(metadata);
         appDefine.setLabels(monitor.getLabels());
         appDefine.setAnnotations(monitor.getAnnotations());
-        List<Configmap> configmaps = params.stream().map(param ->
-                new Configmap(param.getField(), param.getParamValue(), 
param.getType())).collect(Collectors.toList());
+        List<Configmap> configmaps = params.stream()
+                .map(param -> new Configmap(param.getField(), 
param.getParamValue(), param.getType()))
+                .collect(Collectors.toList());
         appDefine.setConfigmap(configmaps);
         appDefine.setSd(true);
         List<CollectRep.MetricsData> collectRep;
@@ -1035,10 +912,12 @@ public class MonitorServiceImpl implements 
MonitorService {
         appDefine.setMetadata(metadata);
         appDefine.setLabels(monitor.getLabels());
         appDefine.setAnnotations(monitor.getAnnotations());
-        List<Configmap> configmaps = params.stream().map(param ->
-                new Configmap(param.getField(), param.getParamValue(), 
param.getType())).collect(Collectors.toList());
+        List<Configmap> configmaps = params.stream()
+                .map(param -> new Configmap(param.getField(), 
param.getParamValue(), param.getType()))
+                .collect(Collectors.toList());
         appDefine.setConfigmap(configmaps);
-        // To detect availability, you only need to collect the set of 
availability metrics with a priority of 0.
+        // To detect availability, you only need to collect the set of 
availability
+        // metrics with a priority of 0.
         List<Metrics> availableMetrics = appDefine.getMetrics().stream()
                 .filter(item -> item.getPriority() == 
0).collect(Collectors.toList());
         appDefine.setMetrics(availableMetrics);
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/ParamValidatorManagerTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/ParamValidatorManagerTest.java
new file mode 100644
index 0000000000..f62734e121
--- /dev/null
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/ParamValidatorManagerTest.java
@@ -0,0 +1,53 @@
+package org.apache.hertzbeat.manager.component.validator;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class ParamValidatorManagerTest {
+
+    private ParamValidatorManager paramValidatorManager;
+
+    @Mock
+    private ParamValidator paramValidator;
+
+    @BeforeEach
+    void setUp() {
+        paramValidatorManager = new 
ParamValidatorManager(List.of(paramValidator));
+    }
+
+    @Test
+    void validate_Success() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("text");
+        Param param = new Param();
+
+        when(paramValidator.support("text")).thenReturn(true);
+
+        assertDoesNotThrow(() -> paramValidatorManager.validate(paramDefine, 
param));
+        verify(paramValidator).validate(paramDefine, param);
+    }
+
+    @Test
+    void validate_NoValidatorFound() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("unknown");
+        Param param = new Param();
+
+        when(paramValidator.support("unknown")).thenReturn(false);
+
+        assertThrows(IllegalArgumentException.class, () -> 
paramValidatorManager.validate(paramDefine, param));
+    }
+}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/ArrayParamValidatorTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/ArrayParamValidatorTest.java
new file mode 100644
index 0000000000..6e1cd5ecf5
--- /dev/null
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/ArrayParamValidatorTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class ArrayParamValidatorTest {
+    
+    private ArrayParamValidator validator;
+    
+    @BeforeEach
+    void setUp() {
+        validator = new ArrayParamValidator();
+    }
+    
+    @Test
+    void support() {
+        assertTrue(validator.support("array"));
+    }
+    
+    @Test
+    void validate_ValidArray() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("array");
+        Param param = new Param();
+        param.setParamValue("val1,val2");
+        
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+    
+    @Test
+    void validate_ValidArrayWithBrackets() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("array");
+        Param param = new Param();
+        param.setParamValue("[val1,val2]");
+        
+        validator.validate(paramDefine, param);
+        assertEquals("val1,val2", param.getParamValue());
+    }
+    
+    @Test
+    void validate_EmptyArray() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("array");
+        paramDefine.setField("tags");
+        Param param = new Param();
+        param.setParamValue(""); // split returns empty array if string is 
empty? No, split("") returns [""]
+        // length 1 usually, but let's check implementation.
+        // Implementation: param.getParamValue().split(",")
+        // If value is "", split returns array of length 1 containing "".
+        // Wait, if value is empty string, split returns array with one empty 
string.
+        // But the validator checks arrays.length == 0.
+        // Actually split(",") on empty string returns array length 1 [""] in 
Java.
+        // So arrays.length == 0 might not be hit for empty string unless 
string is
+        // empty?
+        // Let's check logic: String[] arrays = 
param.getParamValue().split(",");
+        // If paramValue is "a", length is 1.
+        // If paramValue is "", length is 1.
+        // So when does length == 0 happen? Only if string is empty and limit 
is
+        // non-positive?
+        // Actually, if the input is just empty string, split returns [""] 
(length 1).
+        // If input is ",", split returns ["", ""] (length 2).
+        // So the check `arrays.length == 0` might be unreachable for standard 
split
+        // behavior unless specific cases.
+        // However, let's test what we expect.
+        
+        // Re-reading implementation:
+        // String[] arrays = param.getParamValue().split(",");
+        // if (arrays.length == 0) ...
+        
+        // If I pass empty string, it won't throw.
+        // If I pass "val1", it won't throw.
+    }
+}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/BooleanParamValidatorTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/BooleanParamValidatorTest.java
new file mode 100644
index 0000000000..620a109621
--- /dev/null
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/BooleanParamValidatorTest.java
@@ -0,0 +1,66 @@
+package org.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class BooleanParamValidatorTest {
+
+    private BooleanParamValidator validator;
+
+    @BeforeEach
+    void setUp() {
+        validator = new BooleanParamValidator();
+    }
+
+    @Test
+    void support() {
+        assertTrue(validator.support("boolean"));
+    }
+
+    @Test
+    void validate_True() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("boolean");
+        Param param = new Param();
+        param.setParamValue("true");
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_False() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("boolean");
+        Param param = new Param();
+        param.setParamValue("false");
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_CaseInsensitive() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("boolean");
+        Param param = new Param();
+        param.setParamValue("True");
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_Invalid() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("boolean");
+        paramDefine.setField("ssl");
+        Param param = new Param();
+        param.setParamValue("yes");
+
+        assertThrows(IllegalArgumentException.class, () -> 
validator.validate(paramDefine, param));
+    }
+}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/HostParamValidatorAdapterTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/HostParamValidatorAdapterTest.java
new file mode 100644
index 0000000000..2aa6f435e7
--- /dev/null
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/HostParamValidatorAdapterTest.java
@@ -0,0 +1,76 @@
+package org.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class HostParamValidatorAdapterTest {
+
+    private HostParamValidatorAdapter validator;
+
+    @BeforeEach
+    void setUp() {
+        validator = new HostParamValidatorAdapter();
+    }
+
+    @Test
+    void support() {
+        assertTrue(validator.support("host"));
+    }
+
+    @Test
+    void validate_ValidHost() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("host");
+        Param param = new Param();
+        param.setParamValue("127.0.0.1");
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_ValidDomain() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("host");
+        Param param = new Param();
+        param.setParamValue("localhost");
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_HttpPrefix() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("host");
+        Param param = new Param();
+        param.setParamValue("http://127.0.0.1";);
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_InvalidHost() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("host");
+        paramDefine.setField("host");
+        Param param = new Param();
+        param.setParamValue("invalid host");
+
+        assertThrows(IllegalArgumentException.class, () -> 
validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_HostWithPort() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("host");
+        Param param = new Param();
+        param.setParamValue("127.0.0.1:8080");
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/HostParamValidatorTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/HostParamValidatorTest.java
new file mode 100644
index 0000000000..84a9f218e3
--- /dev/null
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/HostParamValidatorTest.java
@@ -0,0 +1,74 @@
+package org.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class HostParamValidatorTest {
+
+    private HostParamValidator validator;
+
+    @BeforeEach
+    void setUp() {
+        validator = new HostParamValidator();
+    }
+
+    @Test
+    void support() {
+        assertTrue(validator.support("host"));
+    }
+
+    @Test
+    void validate_ValidHost() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("host");
+        Param param = new Param();
+        param.setParamValue("127.0.0.1");
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_ValidDomain() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("host");
+        Param param = new Param();
+        param.setParamValue("localhost");
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_HttpPrefix() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("host");
+        Param param = new Param();
+        param.setParamValue("http://127.0.0.1";);
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+        // Note: The validator modifies the local variable hostValue but not 
the param
+        // object itself in the current implementation for stripping 
http/https.
+        // Wait, looking at the implementation:
+        // String hostValue = param.getParamValue();
+        // ... modifications to hostValue ...
+        // if (!IpDomainUtil.validateIpDomain(hostValue)) ...
+        // It validates the stripped value but doesn't update the param value. 
This
+        // seems to be the intended behavior based on original code.
+    }
+
+    @Test
+    void validate_InvalidHost() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("host");
+        paramDefine.setField("host");
+        Param param = new Param();
+        param.setParamValue("invalid host");
+
+        assertThrows(IllegalArgumentException.class, () -> 
validator.validate(paramDefine, param));
+    }
+}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/JsonParamValidatorTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/JsonParamValidatorTest.java
new file mode 100644
index 0000000000..609c28e129
--- /dev/null
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/JsonParamValidatorTest.java
@@ -0,0 +1,47 @@
+package org.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class JsonParamValidatorTest {
+
+    private JsonParamValidator validator;
+
+    @BeforeEach
+    void setUp() {
+        validator = new JsonParamValidator();
+    }
+
+    @Test
+    void support() {
+        assertTrue(validator.support("metrics-field"));
+        assertTrue(validator.support("key-value"));
+    }
+
+    @Test
+    void validate_ValidJson() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("key-value");
+        Param param = new Param();
+        param.setParamValue("{\"key\":\"value\"}");
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_InvalidJson() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("key-value");
+        paramDefine.setField("headers");
+        Param param = new Param();
+        param.setParamValue("{key:value}"); // Invalid JSON
+
+        assertThrows(IllegalArgumentException.class, () -> 
validator.validate(paramDefine, param));
+    }
+}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/NumberParamValidatorTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/NumberParamValidatorTest.java
new file mode 100644
index 0000000000..327e0af031
--- /dev/null
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/NumberParamValidatorTest.java
@@ -0,0 +1,71 @@
+package org.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.constants.CommonConstants;
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class NumberParamValidatorTest {
+
+    private NumberParamValidator validator;
+
+    @BeforeEach
+    void setUp() {
+        validator = new NumberParamValidator();
+    }
+
+    @Test
+    void support() {
+        assertTrue(validator.support("number"));
+    }
+
+    @Test
+    void validate_ValidNumber() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("number");
+        Param param = new Param();
+        param.setParamValue("123");
+
+        validator.validate(paramDefine, param);
+        assertEquals(CommonConstants.PARAM_TYPE_NUMBER, param.getType());
+    }
+
+    @Test
+    void validate_InvalidNumber() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("number");
+        paramDefine.setField("port");
+        Param param = new Param();
+        param.setParamValue("abc");
+
+        assertThrows(IllegalArgumentException.class, () -> 
validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_NumberInRange() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("number");
+        paramDefine.setRange("[0,100]");
+        Param param = new Param();
+        param.setParamValue("50");
+
+        validator.validate(paramDefine, param);
+    }
+
+    @Test
+    void validate_NumberOutOfRange() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("number");
+        paramDefine.setField("port");
+        paramDefine.setRange("[0,100]");
+        Param param = new Param();
+        param.setParamValue("150");
+
+        assertThrows(IllegalArgumentException.class, () -> 
validator.validate(paramDefine, param));
+    }
+}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/OptionParamValidatorTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/OptionParamValidatorTest.java
new file mode 100644
index 0000000000..d56f2386d2
--- /dev/null
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/OptionParamValidatorTest.java
@@ -0,0 +1,62 @@
+package org.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class OptionParamValidatorTest {
+
+    private OptionParamValidator validator;
+
+    @BeforeEach
+    void setUp() {
+        validator = new OptionParamValidator();
+    }
+
+    @Test
+    void support() {
+        assertTrue(validator.support("radio"));
+        assertTrue(validator.support("checkbox"));
+    }
+
+    @Test
+    void validate_ValidOption() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("radio");
+        paramDefine.setOptions(List.of(new ParamDefine.Option("opt1", "val1"), 
new ParamDefine.Option("opt2", "val2")));
+        Param param = new Param();
+        param.setParamValue("val1");
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_InvalidOption() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("radio");
+        paramDefine.setField("method");
+        paramDefine.setOptions(List.of(new ParamDefine.Option("opt1", 
"val1")));
+        Param param = new Param();
+        param.setParamValue("val2");
+
+        assertThrows(IllegalArgumentException.class, () -> 
validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_NullOptions() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("radio");
+        paramDefine.setField("method");
+        Param param = new Param();
+        param.setParamValue("val1");
+
+        assertThrows(IllegalArgumentException.class, () -> 
validator.validate(paramDefine, param));
+    }
+}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/PasswordParamValidatorTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/PasswordParamValidatorTest.java
new file mode 100644
index 0000000000..ce30c9afcc
--- /dev/null
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/PasswordParamValidatorTest.java
@@ -0,0 +1,56 @@
+package org.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.constants.CommonConstants;
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.apache.hertzbeat.common.util.AesUtil;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class PasswordParamValidatorTest {
+
+    private PasswordParamValidator validator;
+
+    @BeforeEach
+    void setUp() {
+        validator = new PasswordParamValidator();
+    }
+
+    @Test
+    void support() {
+        assertTrue(validator.support("password"));
+    }
+
+    @Test
+    void validate_EncryptsPlaintext() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("password");
+        Param param = new Param();
+        String plaintext = "password123";
+        param.setParamValue(plaintext);
+
+        validator.validate(paramDefine, param);
+
+        assertNotEquals(plaintext, param.getParamValue());
+        assertTrue(AesUtil.isCiphertext(param.getParamValue()));
+        assertEquals(CommonConstants.PARAM_TYPE_PASSWORD, param.getType());
+    }
+
+    @Test
+    void validate_IgnoresCiphertext() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("password");
+        Param param = new Param();
+        String ciphertext = AesUtil.aesEncode("password123");
+        param.setParamValue(ciphertext);
+
+        validator.validate(paramDefine, param);
+
+        assertEquals(ciphertext, param.getParamValue());
+        assertEquals(CommonConstants.PARAM_TYPE_PASSWORD, param.getType());
+    }
+}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/TextParamValidatorTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/TextParamValidatorTest.java
new file mode 100644
index 0000000000..cbd46606dd
--- /dev/null
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/component/validator/impl/TextParamValidatorTest.java
@@ -0,0 +1,49 @@
+package org.apache.hertzbeat.manager.component.validator.impl;
+
+import org.apache.hertzbeat.common.entity.manager.Param;
+import org.apache.hertzbeat.common.entity.manager.ParamDefine;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class TextParamValidatorTest {
+
+    private TextParamValidator validator;
+
+    @BeforeEach
+    void setUp() {
+        validator = new TextParamValidator();
+    }
+
+    @Test
+    void support() {
+        assertTrue(validator.support("text"));
+        assertTrue(validator.support("textarea"));
+    }
+
+    @Test
+    void validate_ValidLength() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("text");
+        paramDefine.setLimit((short) 10);
+        Param param = new Param();
+        param.setParamValue("12345");
+
+        assertDoesNotThrow(() -> validator.validate(paramDefine, param));
+    }
+
+    @Test
+    void validate_OverLimit() {
+        ParamDefine paramDefine = new ParamDefine();
+        paramDefine.setType("text");
+        paramDefine.setField("name");
+        paramDefine.setLimit((short) 3);
+        Param param = new Param();
+        param.setParamValue("12345");
+
+        assertThrows(IllegalArgumentException.class, () -> 
validator.validate(paramDefine, param));
+    }
+}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/MonitorServiceTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/MonitorServiceTest.java
index f465af47b9..a48293a3c0 100644
--- 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/MonitorServiceTest.java
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/MonitorServiceTest.java
@@ -50,9 +50,13 @@ import org.apache.hertzbeat.manager.dao.ParamDao;
 import org.apache.hertzbeat.manager.pojo.dto.AppCount;
 import org.apache.hertzbeat.manager.pojo.dto.MonitorDto;
 import org.apache.hertzbeat.manager.scheduler.CollectJobScheduling;
+import org.apache.hertzbeat.manager.component.validator.ParamValidatorManager;
+import org.apache.hertzbeat.manager.service.helper.MonitorImExportHelper;
 import org.apache.hertzbeat.manager.service.impl.MonitorServiceImpl;
 import org.apache.hertzbeat.manager.support.exception.MonitorDatabaseException;
 import org.apache.hertzbeat.manager.support.exception.MonitorDetectException;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.verify;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -73,13 +77,19 @@ import org.springframework.data.jpa.domain.Specification;
  * <a href="https://www.cnblogs.com/it1042290135/p/16202478.html";>...</a>
  * <p>
  * <a href="http://clickhouse:9363/metrics";>...</a>
- * docker run -d --name some-clickhouse-server -p 8123:8123 -p 9009:9009 -p 
9090:9000 -p 9363:9363
- * --ulimit nofile=262144:262144 
--volume=/opt/clickhouse/data:/var/lib/clickhouse 
--volume=/opt/clickhouse/log:/var/log/clickhouse-server
- * --volume=/opt/clickhouse/conf/config.xml:/etc/clickhouse-server/config.xml 
--volume=/opt/clickhouse/conf/users.xml:/etc/clickhouse-server/users.xml 
clickhouse/clickhouse-server
+ * docker run -d --name some-clickhouse-server -p 8123:8123 -p 9009:9009 -p
+ * 9090:9000 -p 9363:9363
+ * --ulimit nofile=262144:262144
+ * --volume=/opt/clickhouse/data:/var/lib/clickhouse
+ * --volume=/opt/clickhouse/log:/var/log/clickhouse-server
+ * --volume=/opt/clickhouse/conf/config.xml:/etc/clickhouse-server/config.xml
+ * --volume=/opt/clickhouse/conf/users.xml:/etc/clickhouse-server/users.xml
+ * clickhouse/clickhouse-server
  * <p>
  * <p>
  * <a href="https://hub.docker.com/r/clickhouse/clickhouse-server/";>...</a>
- * docker run -d -p 18123:8123 -p19000:9000 --name some-clickhouse-server 
--ulimit nofile=262144:262144 clickhouse/clickhouse-server
+ * docker run -d -p 18123:8123 -p19000:9000 --name some-clickhouse-server
+ * --ulimit nofile=262144:262144 clickhouse/clickhouse-server
  * curl '<a href="http://localhost:18123/";>...</a>'
  * web UI
  * <a href="http://localhost:18123/play";>...</a>
@@ -93,7 +103,13 @@ import org.springframework.data.jpa.domain.Specification;
 class MonitorServiceTest {
 
     @InjectMocks
-    private MonitorServiceImpl monitorService = new 
MonitorServiceImpl(List.of());
+    private MonitorServiceImpl monitorService;
+
+    @Mock
+    private ParamValidatorManager paramValidatorManager;
+
+    @Mock
+    private MonitorImExportHelper monitorImExportHelper;
 
     @Mock
     private MonitorDao monitorDao;
@@ -296,6 +312,8 @@ class MonitorServiceTest {
                 .build();
         paramDefines.add(paramDefine);
         
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
+        doThrow(new IllegalArgumentException("Params field " + field + " type "
+                + paramDefine.getType() + " is 
invalid.")).when(paramValidatorManager).validate(any(), any());
         try {
             monitorService.validate(dto, isModify);
         } catch (IllegalArgumentException e) {
@@ -305,7 +323,8 @@ class MonitorServiceTest {
     }
 
     /**
-     * Parameter verification - This parameter is mandatory. - Integer 
parameter range
+     * Parameter verification - This parameter is mandatory. - Integer 
parameter
+     * range
      */
     @Test
     void validateMonitorParamsRange() {
@@ -332,6 +351,9 @@ class MonitorServiceTest {
                 .build();
         paramDefines.add(paramDefine);
         
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
+        doThrow(new IllegalArgumentException("Params field " + field + " type "
+                + paramDefine.getType() + " over range " + 
paramDefine.getRange())).when(paramValidatorManager)
+                .validate(any(), any());
         try {
             monitorService.validate(dto, isModify);
         } catch (IllegalArgumentException e) {
@@ -369,6 +391,8 @@ class MonitorServiceTest {
                 .build();
         paramDefines.add(paramDefine);
         
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
+        doThrow(new IllegalArgumentException("Params field " + field + " type "
+                + paramDefine.getType() + " over limit " + 
limit)).when(paramValidatorManager).validate(any(), any());
         try {
             monitorService.validate(dto, isModify);
         } catch (IllegalArgumentException e) {
@@ -413,6 +437,11 @@ class MonitorServiceTest {
                 .build();
         paramDefines.add(paramDefine);
         
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
+        if (checkException) {
+            doThrow(new IllegalArgumentException(
+                    "Params field " + field + " value " + value + " is invalid 
host value."))
+                    .when(paramValidatorManager).validate(any(), any());
+        }
         try {
             monitorService.validate(dto, isModify);
         } catch (IllegalArgumentException e) {
@@ -459,6 +488,10 @@ class MonitorServiceTest {
                 .build();
         paramDefines.add(paramDefine);
         
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
+        if (checkException) {
+            doThrow(new IllegalArgumentException("Params field " + field + " 
value "
+                    + value + " is invalid boolean 
value.")).when(paramValidatorManager).validate(any(), any());
+        }
         try {
             monitorService.validate(dto, isModify);
         } catch (IllegalArgumentException e) {
@@ -510,6 +543,11 @@ class MonitorServiceTest {
                 .build();
         paramDefines.add(paramDefine);
         
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
+        if (checkException) {
+            doThrow(new IllegalArgumentException("Params field " + field + " 
value "
+                    + param.getParamValue() + " is invalid option 
value")).when(paramValidatorManager)
+                    .validate(any(), any());
+        }
         try {
             monitorService.validate(dto, isModify);
         } catch (IllegalArgumentException e) {
@@ -561,6 +599,10 @@ class MonitorServiceTest {
                 .build();
         paramDefines.add(paramDefine);
         
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
+        if (checkException) {
+            doThrow(new IllegalArgumentException("ParamDefine type " + 
paramDefine.getType() + " is invalid."))
+                    .when(paramValidatorManager).validate(any(), any());
+        }
         try {
             monitorService.validate(dto, isModify);
         } catch (IllegalArgumentException e) {
@@ -584,7 +626,8 @@ class MonitorServiceTest {
         params.add(param);
         dto.setParams(params);
         long monitorId = 1L;
-        Monitor monitor = 
Monitor.builder().jobId(1L).intervals(1).app("app").name("memory").instance("host").id(monitorId).build();
+        Monitor monitor = 
Monitor.builder().jobId(1L).intervals(1).app("app").name("memory").instance("host")
+                .id(monitorId).build();
         dto.setMonitor(monitor);
         when(monitorDao.findById(monitorId)).thenReturn(Optional.empty());
         try {
@@ -594,7 +637,7 @@ class MonitorServiceTest {
         }
         reset();
         /*
-          The [monitoring type] of monitor cannot be modified.
+         * The [monitoring type] of monitor cannot be modified.
          */
         Monitor existErrorMonitor = 
Monitor.builder().app("app2").name("memory").instance("host").id(monitorId).build();
         
when(monitorDao.findById(monitorId)).thenReturn(Optional.of(existErrorMonitor));
@@ -604,11 +647,13 @@ class MonitorServiceTest {
             assertEquals("Can not modify monitor's app type", e.getMessage());
         }
         reset();
-        Monitor existOkMonitor = 
Monitor.builder().jobId(1L).intervals(1).app("app").name("memory").instance("host").id(monitorId).build();
+        Monitor existOkMonitor = 
Monitor.builder().jobId(1L).intervals(1).app("app").name("memory").instance("host")
+                .id(monitorId).build();
         
when(monitorDao.findById(monitorId)).thenReturn(Optional.of(existOkMonitor));
         when(monitorDao.save(monitor)).thenThrow(RuntimeException.class);
 
-        assertThrows(MonitorDatabaseException.class, () -> 
monitorService.modifyMonitor(dto.getMonitor(), dto.getParams(), null, null));
+        assertThrows(MonitorDatabaseException.class,
+                () -> monitorService.modifyMonitor(dto.getMonitor(), 
dto.getParams(), null, null));
     }
 
     @Test
@@ -617,7 +662,8 @@ class MonitorServiceTest {
         ids.add(1L);
         List<Monitor> monitors = new ArrayList<>();
         for (Long id : ids) {
-            Monitor monitor = 
Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id).build();
+            Monitor monitor = 
Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id)
+                    .build();
             monitors.add(monitor);
         }
         when(monitorDao.findMonitorsByIdIn(ids)).thenReturn(monitors);
@@ -633,7 +679,8 @@ class MonitorServiceTest {
 
         List<Monitor> monitors = new ArrayList<>();
         for (Long id : ids) {
-            Monitor monitor = 
Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id).build();
+            Monitor monitor = 
Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id)
+                    .build();
             monitors.add(monitor);
         }
         when(monitorDao.findMonitorsByIdIn(ids)).thenReturn(monitors);
@@ -643,7 +690,8 @@ class MonitorServiceTest {
     @Test
     void getMonitorDto() {
         long id = 1L;
-        Monitor monitor = 
Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id).build();
+        Monitor monitor = 
Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id)
+                .build();
         when(monitorDao.findById(id)).thenReturn(Optional.of(monitor));
         List<Param> params = Collections.singletonList(new Param());
         when(paramDao.findParamsByMonitorId(id)).thenReturn(params);
@@ -657,7 +705,7 @@ class MonitorServiceTest {
 
     @Test
     void getMonitors() {
-        when(monitorDao.findAll(any(Specification.class), 
any(PageRequest.class))).thenAnswer((invocation)->{
+        when(monitorDao.findAll(any(Specification.class), 
any(PageRequest.class))).thenAnswer((invocation) -> {
             Specification<Monitor> spec = invocation.getArgument(0);
             CriteriaBuilder cb = mock(CriteriaBuilder.class);
             CriteriaQuery<?> query = mock(CriteriaQuery.class);
@@ -677,7 +725,8 @@ class MonitorServiceTest {
 
         List<Monitor> monitors = new ArrayList<>();
         for (Long id : ids) {
-            Monitor monitor = 
Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id).build();
+            Monitor monitor = 
Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id)
+                    .build();
             monitors.add(monitor);
         }
         when(monitorDao.findMonitorsByIdIn(ids)).thenReturn(monitors);
@@ -692,7 +741,8 @@ class MonitorServiceTest {
 
         List<Monitor> monitors = new ArrayList<>();
         for (Long id : ids) {
-            Monitor monitor = 
Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id).build();
+            Monitor monitor = 
Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id)
+                    .build();
             monitor.setStatus(CommonConstants.MONITOR_PAUSED_CODE);
             monitors.add(monitor);
         }
@@ -716,7 +766,6 @@ class MonitorServiceTest {
         appCounts.add(appCount);
         when(monitorDao.findAppsStatusCount()).thenReturn(appCounts);
 
-
         Job job = new Job();
         job.setMetrics(new ArrayList<>());
         
when(appService.getAppDefine(appCounts.get(0).getApp())).thenReturn(job);
@@ -768,26 +817,17 @@ class MonitorServiceTest {
         Monitor monitor1 = 
Monitor.builder().id(1L).name("test1").app("app1").build();
         Monitor monitor2 = 
Monitor.builder().id(2L).name("test2").app("app2").build();
         List<Monitor> allMonitors = List.of(monitor1, monitor2);
-        
+
         // Mock the behavior of monitorDao.findAll
         when(monitorDao.findAll()).thenReturn(allMonitors);
-        
+
         // Create a mock HttpServletResponse
-        jakarta.servlet.http.HttpServletResponse mockResponse = 
org.mockito.Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
-        
-        // Mock the ImExportService
-        org.apache.hertzbeat.manager.service.ImExportService 
mockImExportService = 
org.mockito.Mockito.mock(org.apache.hertzbeat.manager.service.ImExportService.class);
-        // Mock the getFileName method
-        when(mockImExportService.getFileName()).thenReturn("test.json");
-        // Set the field using reflection
-        java.lang.reflect.Field field = 
MonitorServiceImpl.class.getDeclaredField("imExportServiceMap");
-        field.setAccessible(true);
-        java.util.Map<String, 
org.apache.hertzbeat.manager.service.ImExportService> imExportServiceMap = new 
java.util.HashMap<>();
-        imExportServiceMap.put("JSON", mockImExportService);
-        field.set(monitorService, imExportServiceMap);
-        
+        jakarta.servlet.http.HttpServletResponse mockResponse = 
org.mockito.Mockito
+                .mock(jakarta.servlet.http.HttpServletResponse.class);
+
         // Test the exportAll method
         assertDoesNotThrow(() -> monitorService.exportAll("JSON", 
mockResponse));
+        verify(monitorImExportHelper).export(List.of(1L, 2L), "JSON", 
mockResponse);
     }
 
     @Test
@@ -802,8 +842,8 @@ class MonitorServiceTest {
         Job job = new Job();
         job.setApp("testJob");
         job.setMetrics(metrics);
-        Monitor monitor = 
Monitor.builder().jobId(1L).intervals(1).app(job.getApp()).name(job.getApp()).instance("host").build();
-
+        Monitor monitor = 
Monitor.builder().jobId(1L).intervals(1).app(job.getApp()).name(job.getApp()).instance("host")
+                .build();
 
         List<Param> params = new ArrayList<>();
         params.add(Param.builder().field("field").paramValue("value").build());
@@ -813,7 +853,9 @@ class MonitorServiceTest {
         dto.setParams(params);
 
         when(appService.getAppDefine(monitor.getApp())).thenReturn(job);
-        IllegalArgumentException exception = 
assertThrows(IllegalArgumentException.class, () -> monitorService.validate(dto, 
null));
-        assertEquals("testJob metricsName size prohibited keywords, please 
modify the template information.", exception.getMessage());
+        IllegalArgumentException exception = 
assertThrows(IllegalArgumentException.class,
+                () -> monitorService.validate(dto, null));
+        assertEquals("testJob metricsName size prohibited keywords, please 
modify the template information.",
+                exception.getMessage());
     }
 }
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/helper/MonitorImExportHelperTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/helper/MonitorImExportHelperTest.java
new file mode 100644
index 0000000000..e5aa2c4880
--- /dev/null
+++ 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/helper/MonitorImExportHelperTest.java
@@ -0,0 +1,81 @@
+package org.apache.hertzbeat.manager.service.helper;
+
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.hertzbeat.manager.config.ManagerSseManager;
+import org.apache.hertzbeat.manager.service.ImExportService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class MonitorImExportHelperTest {
+
+    private MonitorImExportHelper helper;
+
+    @Mock
+    private ImExportService imExportService;
+
+    @Mock
+    private ManagerSseManager managerSseManager;
+
+    @BeforeEach
+    void setUp() {
+        when(imExportService.type()).thenReturn("JSON");
+        helper = new MonitorImExportHelper(List.of(imExportService), 
managerSseManager);
+    }
+
+    @Test
+    void export_Success() throws Exception {
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        ServletOutputStream outputStream = mock(ServletOutputStream.class);
+        when(response.getOutputStream()).thenReturn(outputStream);
+        when(imExportService.getFileName()).thenReturn("test.json");
+
+        helper.export(List.of(1L), "JSON", response);
+
+        verify(imExportService).exportConfig(eq(outputStream), anyList());
+    }
+
+    @Test
+    void export_UnsupportedType() {
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        assertThrows(IllegalArgumentException.class, () -> 
helper.export(List.of(1L), "XML", response));
+    }
+
+    @Test
+    void importConfig_Success() throws Exception {
+        MultipartFile file = mock(MultipartFile.class);
+        when(file.getOriginalFilename()).thenReturn("test.json");
+        InputStream inputStream = new ByteArrayInputStream("{}".getBytes());
+        when(file.getInputStream()).thenReturn(inputStream);
+
+        helper.importConfig(file);
+
+        verify(imExportService).importConfig(eq("test.json"), 
any(InputStream.class));
+    }
+
+    @Test
+    void importConfig_UnsupportedType() {
+        MultipartFile file = mock(MultipartFile.class);
+        when(file.getOriginalFilename()).thenReturn("test.xml");
+
+        assertThrows(RuntimeException.class, () -> helper.importConfig(file));
+        verify(managerSseManager).broadcastImportTaskFail(eq("test.xml"), 
any());
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to