diff --git a/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java b/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java index 8c789664..d3fa5336 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java @@ -6,6 +6,7 @@ import com.reajason.javaweb.memshell.ServerFactory; import com.reajason.javaweb.memshell.config.CommandConfig; import com.reajason.javaweb.memshell.server.AbstractServer; import com.reajason.javaweb.packer.Packers; +import com.reajason.javaweb.probe.generator.response.ResponseBodyGenerator; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -22,7 +23,12 @@ import java.util.*; @CrossOrigin("*") public class ConfigController { + /** + * @deprecated use {@link #config()} for memshell configuration and + * {@link #getProbeResponseBodyServers()} for probe ResponseBody servers. + */ @RequestMapping("/servers") + @Deprecated(since = "2.9.0", forRemoval = false) public Map> getServers() { Map> servers = new LinkedHashMap<>(); List supportedServers = ServerFactory.getSupportedServers(); @@ -34,7 +40,11 @@ public class ConfigController { return servers; } + /** + * @deprecated use {@link #getPackerTree()} for parent/child packer metadata. + */ @RequestMapping("/packers") + @Deprecated(since = "2.9.0", forRemoval = false) public List getPackers() { return Arrays.stream(Packers.values()) .filter(packers -> packers.getParentPacker() == null) @@ -56,9 +66,14 @@ public class ConfigController { .toList(); } + @RequestMapping("/probe/response-body/servers") + public List getProbeResponseBodyServers() { + return ResponseBodyGenerator.getSupportedServers(); + } + @RequestMapping public Map> config() { - Map> coreMap = new HashMap<>(16); + Map> coreMap = new LinkedHashMap<>(16); List supportedServers = ServerFactory.getSupportedServers(); for (String supportedServer : supportedServers) { AbstractServer server = ServerFactory.getServer(supportedServer); @@ -82,4 +97,4 @@ public class ConfigController { commandConfigVO.setImplementationClasses(Arrays.stream(CommandConfig.ImplementationClass.values()).toList()); return commandConfigVO; } -} \ No newline at end of file +} diff --git a/boot/src/test/java/com/reajason/javaweb/boot/controller/ConfigControllerIntegrationTest.java b/boot/src/test/java/com/reajason/javaweb/boot/controller/ConfigControllerIntegrationTest.java index 9fdf676a..3ae6a05a 100644 --- a/boot/src/test/java/com/reajason/javaweb/boot/controller/ConfigControllerIntegrationTest.java +++ b/boot/src/test/java/com/reajason/javaweb/boot/controller/ConfigControllerIntegrationTest.java @@ -1,9 +1,12 @@ package com.reajason.javaweb.boot.controller; -import org.junit.jupiter.api.Test; +import com.reajason.javaweb.memshell.ServerFactory; +import com.reajason.javaweb.probe.generator.response.ResponseBodyGenerator; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestClient; @@ -22,6 +25,12 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class ConfigControllerIntegrationTest { + private static final ParameterizedTypeReference> MAP_TYPE = new ParameterizedTypeReference<>() { + }; + + private static final ParameterizedTypeReference> STRING_LIST_TYPE = new ParameterizedTypeReference<>() { + }; + @LocalServerPort private int port; @@ -36,31 +45,44 @@ public class ConfigControllerIntegrationTest { @Test public void testConfigEndpoint() { - ResponseEntity response = restClient.get() + ResponseEntity> response = restClient.get() .uri("/api/config") .retrieve() - .toEntity(Map.class); + .toEntity(MAP_TYPE); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); + assertEquals(ServerFactory.getSupportedServers(), List.copyOf(response.getBody().keySet())); } @Test public void testConfigServersEndpoint() { - ResponseEntity response = restClient.get() + ResponseEntity> response = restClient.get() .uri("/api/config/servers") .retrieve() - .toEntity(Map.class); + .toEntity(MAP_TYPE); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertNotNull(response.getBody()); + assertEquals(ServerFactory.getSupportedServers(), List.copyOf(response.getBody().keySet())); + } + + @Test + public void testConfigPackersEndpoint() { + ResponseEntity> response = restClient.get() + .uri("/api/config/packers") + .retrieve() + .toEntity(STRING_LIST_TYPE); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); } @Test - public void testConfigPackersEndpoint() { - ResponseEntity response = restClient.get() - .uri("/api/config/packers") + public void testConfigProbeResponseBodyServersEndpoint() { + ResponseEntity> response = restClient.get() + .uri("/api/config/probe/response-body/servers") .retrieve() - .toEntity(List.class); + .toEntity(STRING_LIST_TYPE); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); + assertEquals(ResponseBodyGenerator.getSupportedServers(), response.getBody()); } } diff --git a/generator/src/main/java/com/reajason/javaweb/probe/generator/response/ResponseBodyGenerator.java b/generator/src/main/java/com/reajason/javaweb/probe/generator/response/ResponseBodyGenerator.java index f21f0af4..5fc1914e 100644 --- a/generator/src/main/java/com/reajason/javaweb/probe/generator/response/ResponseBodyGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/probe/generator/response/ResponseBodyGenerator.java @@ -23,6 +23,10 @@ import org.apache.commons.lang3.StringUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import static java.nio.charset.StandardCharsets.UTF_8; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -32,10 +36,16 @@ import static net.bytebuddy.matcher.ElementMatchers.named; * @since 2025/6/29 */ public class ResponseBodyGenerator extends ByteBuddyShellGenerator { + private static final Map> WRITER_CLASSES = createWriterClasses(); + public ResponseBodyGenerator(ProbeConfig probeConfig, ResponseBodyConfig probeContentConfig) { super(probeConfig, probeContentConfig); } + public static List getSupportedServers() { + return new ArrayList<>(WRITER_CLASSES.keySet()); + } + @Override protected DynamicType.Builder build(ByteBuddy buddy) { Class getDataFromReqInterceptor = getDataFromReqInterceptor.class; @@ -82,38 +92,32 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator getWriterClass() { - switch (probeContentConfig.getServer()) { - case Server.SpringWebMvc: - return SpringWebMvcWriter.class; - case Server.Jetty: - case Server.Jetty5: - return JettyWriter.class; - case Server.Tomcat: - case Server.JBoss: - case Server.BES: - return TomcatWriter.class; - case Server.TongWeb: - return TongWebWriter.class; - case Server.Resin: - return ResinWriter.class; - case Server.Resin2: - return Resin2Writer.class; - case Server.Undertow: - return UndertowWriter.class; - case Server.GlassFish: - case Server.InforSuite: - return GlassFishWriter.class; - case Server.WebSphere: - return WebSphereWriter.class; - case Server.WebLogic: - return WebLogicWriter.class; - case Server.Apusic: - return ApusicWriter.class; - case Server.Struts2: - return Struts2Writer.class; - default: - throw new GenerationException("responseBody not supported for server: " + probeContentConfig.getServer()); + Class writerClass = WRITER_CLASSES.get(probeContentConfig.getServer()); + if (writerClass == null) { + throw new GenerationException("responseBody not supported for server: " + probeContentConfig.getServer()); } + return writerClass; + } + + private static Map> createWriterClasses() { + Map> writerClasses = new LinkedHashMap<>(); + writerClasses.put(Server.Tomcat, TomcatWriter.class); + writerClasses.put(Server.Jetty, JettyWriter.class); + writerClasses.put(Server.Jetty5, JettyWriter.class); + writerClasses.put(Server.Undertow, UndertowWriter.class); + writerClasses.put(Server.JBoss, TomcatWriter.class); + writerClasses.put(Server.Resin, ResinWriter.class); + writerClasses.put(Server.Resin2, Resin2Writer.class); + writerClasses.put(Server.WebLogic, WebLogicWriter.class); + writerClasses.put(Server.WebSphere, WebSphereWriter.class); + writerClasses.put(Server.GlassFish, GlassFishWriter.class); + writerClasses.put(Server.TongWeb, TongWebWriter.class); + writerClasses.put(Server.BES, TomcatWriter.class); + writerClasses.put(Server.InforSuite, GlassFishWriter.class); + writerClasses.put(Server.Apusic, ApusicWriter.class); + writerClasses.put(Server.SpringWebMvc, SpringWebMvcWriter.class); + writerClasses.put(Server.Struts2, Struts2Writer.class); + return writerClasses; } static class getDataFromReqInterceptor { @@ -181,5 +185,3 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator; - servers?: ServerConfig; }>) { const { t } = useTranslation(["common", "memshell"]); @@ -60,7 +58,7 @@ export default function MainConfigCard({ return mainConfig[server]; }, [mainConfig, server]); - const serverOptions = useMemo(() => Object.keys(servers ?? {}), [servers]); + const serverOptions = useMemo(() => Object.keys(mainConfig ?? {}), [mainConfig]); const shellTools = useMemo(() => { if (!serverToolMap) { @@ -71,11 +69,11 @@ export default function MainConfigCard({ }, [serverToolMap]); const customShellTypes = useMemo(() => { - if (!server) { + if (!serverToolMap) { return []; } - return servers?.[server] ?? []; - }, [server, servers]); + return Array.from(new Set(Object.values(serverToolMap).flat())); + }, [serverToolMap]); const shellTypes = useMemo(() => { if (!serverToolMap || !server) { diff --git a/web/app/components/probeshell/main-config-card.tsx b/web/app/components/probeshell/main-config-card.tsx index 46cf0c3b..dbc8d7c5 100644 --- a/web/app/components/probeshell/main-config-card.tsx +++ b/web/app/components/probeshell/main-config-card.tsx @@ -1,4 +1,3 @@ -import type { ServerConfig } from "@/types/memshell"; import type { ProbeShellFormSchema } from "@/types/schema"; import { InfoIcon, ServerIcon } from "lucide-react"; @@ -62,10 +61,10 @@ const DEFAULT_FORM_VALUES = { interface MainConfigCardProps { readonly form: UseFormReturn; - readonly servers?: ServerConfig; + readonly responseBodyServers?: string[]; } -export default function MainConfigCard({ form, servers }: MainConfigCardProps) { +export default function MainConfigCard({ form, responseBodyServers }: MainConfigCardProps) { const { t } = useTranslation(["common", "probeshell"]); const watchedProbeMethod = form.watch("probeMethod"); const watchedProbeContent = form.watch("probeContent"); @@ -155,13 +154,11 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) { - {Object.keys(servers ?? {}) - .filter((s) => s !== "SpringWebFlux" && s !== "XXLJOB") - .map((server: string) => ( - - {server} - - ))} + {responseBodyServers?.map((server) => ( + + {server} + + ))} {fieldState.error && } diff --git a/web/app/routes/memshell.tsx b/web/app/routes/memshell.tsx index 4aa61b6e..a4dc6e26 100644 --- a/web/app/routes/memshell.tsx +++ b/web/app/routes/memshell.tsx @@ -18,7 +18,6 @@ import { type MemShellGenerateResponse, type MemShellResult, type PackerConfig, - type ServerConfig, ShellToolType, } from "@/types/memshell"; import { @@ -65,18 +64,11 @@ const fetchJson = async (url: string): Promise => { return response.json() as Promise; }; -const fetchServerConfig = () => fetchJson(`${env.API_URL}/api/config/servers`); - const fetchMainConfig = () => fetchJson(`${env.API_URL}/api/config`); const fetchPackerConfig = () => fetchJson(`${env.API_URL}/api/config/packers/tree`); export default function MemShellPage() { - const { data: serverConfig } = useQuery({ - queryKey: ["serverConfig"], - queryFn: fetchServerConfig, - }); - const { data: mainConfig } = useQuery({ queryKey: ["mainConfig"], queryFn: fetchMainConfig, @@ -145,7 +137,7 @@ export default function MemShellPage() {
- +