diff --git a/backend/framework/plugin/plugin-api-sdk/src/main/java/io/metersphere/plugin/api/spi/AbstractMsTestElement.java b/backend/framework/plugin/plugin-api-sdk/src/main/java/io/metersphere/plugin/api/spi/AbstractMsTestElement.java index ab28bfb079..667662ccb5 100644 --- a/backend/framework/plugin/plugin-api-sdk/src/main/java/io/metersphere/plugin/api/spi/AbstractMsTestElement.java +++ b/backend/framework/plugin/plugin-api-sdk/src/main/java/io/metersphere/plugin/api/spi/AbstractMsTestElement.java @@ -7,9 +7,14 @@ import lombok.Data; import java.util.LinkedList; /** -*@Author: jianxing -*@CreateTime: 2023-10-30 15:08 -*/ + * + *
+ * 该对象传参时,需要传入 polymorphicName 字段,用于区分是哪个协议的组件
+ * 对应协议的组件 polymorphicName 字段,调用 /api/test/protocol/{organizationId} 接口获取
+ * 
+ * @Author: jianxing
+ * @CreateTime: 2023-10-30  15:08
+ */
 @Data
 @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "polymorphicName")
 @JsonIgnoreProperties(ignoreUnknown = true)
diff --git a/backend/framework/plugin/plugin-api-sdk/src/main/java/io/metersphere/plugin/api/spi/AbstractProtocolPlugin.java b/backend/framework/plugin/plugin-api-sdk/src/main/java/io/metersphere/plugin/api/spi/AbstractProtocolPlugin.java
index 2614596d53..97d7e096a0 100644
--- a/backend/framework/plugin/plugin-api-sdk/src/main/java/io/metersphere/plugin/api/spi/AbstractProtocolPlugin.java
+++ b/backend/framework/plugin/plugin-api-sdk/src/main/java/io/metersphere/plugin/api/spi/AbstractProtocolPlugin.java
@@ -7,9 +7,30 @@ package io.metersphere.plugin.api.spi;
  */
 public abstract class AbstractProtocolPlugin extends AbstractApiPlugin {
 
+    private static final String DEFAULT_API_PROTOCOL_SCRIPT_ID = "api";
+    private static final String DEFAULT_ENVIRONMENT_PROTOCOL_SCRIPT_ID = "environment";
+
     /**
      * 返回协议名
      * @return
      */
     abstract public String getProtocol();
+
+    /**
+     * 返回接口协议主页面的脚本的ID,默认为 api
+     * 可以重写此方法,返回自定义的脚本ID
+     * @return
+     */
+    public String getApiProtocolScriptId() {
+        return DEFAULT_API_PROTOCOL_SCRIPT_ID;
+    }
+
+    /**
+     * 返回协议环境配置页面的脚本的ID,默认为 environment
+     * 可以重写此方法,返回自定义的脚本ID
+     * @return
+     */
+    public String getEnvProtocolScriptId() {
+        return DEFAULT_ENVIRONMENT_PROTOCOL_SCRIPT_ID;
+    }
 }
diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java
index feef5c6b87..2adf17048a 100644
--- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java
+++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java
@@ -38,7 +38,6 @@ public class ApiTestController {
         return apiTestService.getProtocols(organizationId);
     }
 
-
     @GetMapping("/mock/{key}")
     @Operation(summary = "获取mock数据")
     public String mock(@PathVariable String key) {
@@ -52,6 +51,18 @@ public class ApiTestController {
         return apiExecuteService.runScript(runRequest);
     }
 
+    @GetMapping("/plugin/script/{pluginId}")
+    @Operation(summary = "获取协议插件的的协议列表")
+    @RequiresPermissions(value = {
+            PermissionConstants.PROJECT_API_DEFINITION_READ,
+            PermissionConstants.PROJECT_API_DEFINITION_CASE_READ,
+            PermissionConstants.PROJECT_API_DEBUG_READ,
+            PermissionConstants.PROJECT_API_SCENARIO_READ
+    }, logical = Logical.OR)
+    public Object getApiProtocolScript(@PathVariable String pluginId) {
+        return apiTestService.getApiProtocolScript(pluginId);
+    }
+
     @PostMapping("/plugin/form/option")
     @Operation(summary = "接口测试-获取插件表单选项")
     @RequiresPermissions(value = {
diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/BinaryBody.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/BinaryBody.java
index 6558b883a2..8487d99d52 100644
--- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/BinaryBody.java
+++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/BinaryBody.java
@@ -9,7 +9,7 @@ import lombok.Data;
  * @CreateTime: 2023-11-06  18:25
  */
 @Data
-public class BinaryBody extends ApiFile{
+public class BinaryBody extends ApiFile {
     /**
      *  描述
      */
diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiTestService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiTestService.java
index 7f1f135624..6cfac1e22d 100644
--- a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiTestService.java
+++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiTestService.java
@@ -6,9 +6,11 @@ import io.metersphere.api.dto.request.http.MsHTTPElement;
 import io.metersphere.plugin.api.dto.ApiPluginOptionsRequest;
 import io.metersphere.plugin.api.dto.ApiPluginSelectOption;
 import io.metersphere.plugin.api.spi.AbstractApiPlugin;
+import io.metersphere.plugin.api.spi.AbstractProtocolPlugin;
 import io.metersphere.sdk.util.BeanUtils;
 import io.metersphere.system.dto.ProtocolDTO;
 import io.metersphere.system.service.ApiPluginService;
+import io.metersphere.system.service.PluginLoadService;
 import io.metersphere.system.utils.ServiceUtils;
 import jakarta.annotation.Resource;
 import org.apache.commons.lang3.StringUtils;
@@ -28,6 +30,8 @@ public class ApiTestService {
 
     @Resource
     private ApiPluginService apiPluginService;
+    @Resource
+    private PluginLoadService pluginLoadService;
 
     public List getProtocols(String orgId) {
         List protocols = apiPluginService.getProtocols(orgId);
@@ -48,10 +52,25 @@ public class ApiTestService {
                 .orElse(null);
         if (pluginWrapper == null || !(pluginWrapper.getPlugin() instanceof AbstractApiPlugin)) {
             // 插件不存在或者非接口插件,抛出异常
-            ServiceUtils.checkResourceExist(null, "permission.api_plugin.name");
+            checkResourceExist(null);
         }
         ApiPluginOptionsRequest optionsRequest = BeanUtils.copyBean(new ApiPluginOptionsRequest(), request);
         assert pluginWrapper != null;
         return ((AbstractApiPlugin) pluginWrapper.getPlugin()).getPluginOptions(optionsRequest);
     }
+
+    public Object getApiProtocolScript(String pluginId) {
+        PluginWrapper pluginWrapper = pluginLoadService.getPluginWrapper(pluginId);
+        checkResourceExist(pluginWrapper);
+        if (pluginWrapper.getPlugin() instanceof AbstractProtocolPlugin protocolPlugin) {
+            return pluginLoadService.getPluginScriptContent(pluginId, protocolPlugin.getApiProtocolScriptId());
+        } else {
+            // 插件不存在或者非接口插件,抛出异常
+            return checkResourceExist(null);
+        }
+    }
+
+    public Object checkResourceExist(PluginWrapper pluginWrapper) {
+        return ServiceUtils.checkResourceExist(pluginWrapper, "permission.system_plugin.name");
+    }
 }
\ No newline at end of file
diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestControllerTests.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestControllerTests.java
index 5e583efa68..81462f82b8 100644
--- a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestControllerTests.java
+++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestControllerTests.java
@@ -14,10 +14,7 @@ import io.metersphere.system.dto.request.PluginUpdateRequest;
 import io.metersphere.system.service.PluginService;
 import io.metersphere.system.uid.IDGenerator;
 import jakarta.annotation.Resource;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.MethodOrderer;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.*;
 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.mock.web.MockMultipartFile;
@@ -28,6 +25,7 @@ import java.io.FileInputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import static io.metersphere.sdk.constants.InternalUserRole.ADMIN;
 import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
@@ -46,6 +44,7 @@ public class ApiTestControllerTests extends BaseTest {
     protected static final String MOCK = "mock/{0}";
     protected static final String CUSTOM_FUNC_RUN = "custom/func/run";
     protected static final String PLUGIN_FORM_OPTION = "plugin/form/option";
+    protected static final String PLUGIN_SCRIPT = "plugin/script/{0}";
 
     @Resource
     private BaseResourcePoolTestService baseResourcePoolTestService;
@@ -98,6 +97,7 @@ public class ApiTestControllerTests extends BaseTest {
     }
 
     @Test
+    @Order(10)
     public void getFormOptions() throws Exception {
         ApiTestPluginOptionRequest request = new ApiTestPluginOptionRequest();
         request.setOrgId(DEFAULT_ORGANIZATION_ID);
@@ -127,6 +127,30 @@ public class ApiTestControllerTests extends BaseTest {
         }}, PLUGIN_FORM_OPTION, request);
     }
 
+    @Test
+    @Order(11)
+    public void getApiProtocolScript() throws Exception {
+        assertErrorCode(this.requestGet(PLUGIN_SCRIPT, "aa"), NOT_FOUND);
+        Plugin jiraPlugin = basePluginTestService.addJiraPlugin();
+        assertErrorCode(this.requestGet(PLUGIN_SCRIPT, jiraPlugin.getId()), NOT_FOUND);
+        // @@请求成功
+        Plugin plugin = addTcpTestPlugin();
+        MvcResult mvcResult = this.requestGetWithOkAndReturn(PLUGIN_SCRIPT, plugin.getId());
+        Object resultData = getResultData(mvcResult, Object.class);
+        Assertions.assertNotNull(resultData);
+
+        basePluginTestService.deleteJiraPlugin();
+        pluginService.delete(plugin.getId());
+
+        // @@校验权限
+        requestGetPermissionsTest(new ArrayList<>() {{
+            add(PermissionConstants.PROJECT_API_DEFINITION_READ);
+            add(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ);
+            add(PermissionConstants.PROJECT_API_DEBUG_READ);
+            add(PermissionConstants.PROJECT_API_SCENARIO_READ);
+        }}, PLUGIN_SCRIPT, "11");
+    }
+
     public Plugin addOptionTestPlugin() throws Exception {
         PluginUpdateRequest request = new PluginUpdateRequest();
         File jarFile = new File(
@@ -142,4 +166,19 @@ public class ApiTestControllerTests extends BaseTest {
         return pluginService.add(request, mockMultipartFile);
     }
 
+    public Plugin addTcpTestPlugin() throws Exception {
+        PluginUpdateRequest request = new PluginUpdateRequest();
+        File jarFile = new File(
+                this.getClass().getClassLoader().getResource("file/tcp-sampler-v3.x.jar")
+                        .getPath()
+        );
+        FileInputStream inputStream = new FileInputStream(jarFile);
+        MockMultipartFile mockMultipartFile = new MockMultipartFile(jarFile.getName(), jarFile.getName(), "jar", inputStream);
+        request.setName("测试TCP插件");
+        request.setGlobal(true);
+        request.setEnable(true);
+        request.setCreateUser(ADMIN.name());
+        return pluginService.add(request, mockMultipartFile);
+    }
+
 }
diff --git a/backend/services/api-test/src/test/resources/file/tcp-sampler-v3.x.jar b/backend/services/api-test/src/test/resources/file/tcp-sampler-v3.x.jar
new file mode 100644
index 0000000000..c15a551671
Binary files /dev/null and b/backend/services/api-test/src/test/resources/file/tcp-sampler-v3.x.jar differ
diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/service/EnvironmentService.java b/backend/services/project-management/src/main/java/io/metersphere/project/service/EnvironmentService.java
index c76b767893..ba252852fd 100644
--- a/backend/services/project-management/src/main/java/io/metersphere/project/service/EnvironmentService.java
+++ b/backend/services/project-management/src/main/java/io/metersphere/project/service/EnvironmentService.java
@@ -1,6 +1,7 @@
 package io.metersphere.project.service;
 
 
+import io.metersphere.plugin.api.spi.AbstractProtocolPlugin;
 import io.metersphere.project.domain.Project;
 import io.metersphere.project.domain.ProjectExample;
 import io.metersphere.project.dto.environment.*;
@@ -39,6 +40,7 @@ import jakarta.annotation.Resource;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.pf4j.Plugin;
 import org.pf4j.PluginWrapper;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
@@ -388,13 +390,17 @@ public class EnvironmentService {
 
     public List getPluginScripts(String projectId) {
         Project project = projectService.checkProjectNotExist(projectId);
-        // 查询组织下有权限的接口插件ID
-        List orgApiPluginIds = apiPluginService.getOrgApiPluginWrappers(project.getOrganizationId())
-                .stream()
-                .map(PluginWrapper::getPluginId)
-                .collect(Collectors.toList());
-        // 查询环境页面脚本
-        List pluginScripts = pluginScriptService.getByPluginIdsAndScriptId(orgApiPluginIds, "environment");
+        // 查询组织下有权限的接口插件
+        List orgApiPluginWrappers = apiPluginService.getOrgApiPluginWrappers(project.getOrganizationId());
+
+        // 接口协议环境脚本
+        List pluginScripts = new ArrayList<>(orgApiPluginWrappers.size());
+        orgApiPluginWrappers.stream().forEach(wrapper -> {
+            Plugin plugin = wrapper.getPlugin();
+            if (plugin instanceof AbstractProtocolPlugin protocolPlugin) {
+                pluginScripts.add(pluginScriptService.get(wrapper.getPluginId(), protocolPlugin.getEnvProtocolScriptId()));
+            }
+        });
 
         // 返回环境脚本列表
         return pluginScripts.stream().map(pluginScript -> {
diff --git a/backend/services/project-management/src/test/resources/file/tcp-sampler-v3.x-jar-with-dependencies.jar b/backend/services/project-management/src/test/resources/file/tcp-sampler-v3.x-jar-with-dependencies.jar
index 3c0fe0ccbe..ed67930359 100644
Binary files a/backend/services/project-management/src/test/resources/file/tcp-sampler-v3.x-jar-with-dependencies.jar and b/backend/services/project-management/src/test/resources/file/tcp-sampler-v3.x-jar-with-dependencies.jar differ
diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/service/PluginScriptService.java b/backend/services/system-setting/src/main/java/io/metersphere/system/service/PluginScriptService.java
index bc1efce051..29dc48adb9 100644
--- a/backend/services/system-setting/src/main/java/io/metersphere/system/service/PluginScriptService.java
+++ b/backend/services/system-setting/src/main/java/io/metersphere/system/service/PluginScriptService.java
@@ -64,11 +64,15 @@ public class PluginScriptService {
         pluginScriptMapper.deleteByExample(example);
     }
 
-    public String get(String pluginId, String scriptId) {
-        PluginScript frontScript = pluginScriptMapper.selectByPrimaryKey(pluginId, scriptId);
+    public String getScriptContent(String pluginId, String scriptId) {
+        PluginScript frontScript = get(pluginId, scriptId);
         return frontScript == null ? null : new String(frontScript.getScript());
     }
 
+    public PluginScript get(String pluginId, String scriptId) {
+        return pluginScriptMapper.selectByPrimaryKey(pluginId, scriptId);
+    }
+
     public Map> getScripteMap(List pluginIds) {
         if (CollectionUtils.isEmpty(pluginIds)) {
             return Collections.emptyMap();
@@ -83,15 +87,5 @@ public class PluginScriptService {
             scriptList.add(optionDTO);
         }
         return scriptMap;
-
-    }
-
-    public List getByPluginIdsAndScriptId(List pluginIds, String scriptId) {
-        if (CollectionUtils.isEmpty(pluginIds)) {
-            return Collections.emptyList();
-        }
-        PluginScriptExample example = new PluginScriptExample();
-        example.createCriteria().andScriptIdEqualTo(scriptId);
-        return pluginScriptMapper.selectByExampleWithBLOBs(example);
     }
 }
diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/service/PluginService.java b/backend/services/system-setting/src/main/java/io/metersphere/system/service/PluginService.java
index b66b87b7a9..ae19ab3b83 100644
--- a/backend/services/system-setting/src/main/java/io/metersphere/system/service/PluginService.java
+++ b/backend/services/system-setting/src/main/java/io/metersphere/system/service/PluginService.java
@@ -264,7 +264,7 @@ public class PluginService {
     }
 
     public String getScript(String pluginId, String scriptId) {
-        return pluginScriptService.get(pluginId, scriptId);
+        return pluginScriptService.getScriptContent(pluginId, scriptId);
     }
 
     public void getPluginImg(String pluginId, String filePath, HttpServletResponse response) throws IOException {
diff --git a/backend/services/system-setting/src/test/java/io/metersphere/system/controller/PluginControllerTests.java b/backend/services/system-setting/src/test/java/io/metersphere/system/controller/PluginControllerTests.java
index 96d44abcc9..ca46753578 100644
--- a/backend/services/system-setting/src/test/java/io/metersphere/system/controller/PluginControllerTests.java
+++ b/backend/services/system-setting/src/test/java/io/metersphere/system/controller/PluginControllerTests.java
@@ -317,10 +317,6 @@ public class PluginControllerTests extends BaseTest {
         // @@请求成功
         MvcResult mvcResult = this.requestGetWithOk(SCRIPT_GET, this.addPlugin.getId(), "connect").andReturn();
 
-        // 增加覆盖率
-        pluginScriptService.getByPluginIdsAndScriptId(List.of(), "connect");
-        pluginScriptService.getByPluginIdsAndScriptId(List.of(addPlugin.getId()), "connect");
-
         // 校验数据是否正确
         Assertions.assertTrue(StringUtils.isNotBlank(getResultData(mvcResult, String.class)));
         // @@校验权限