diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/HttpRequestHandler.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/HttpRequestHandler.java index d64af8ab..515e7ca7 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/HttpRequestHandler.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/HttpRequestHandler.java @@ -28,6 +28,8 @@ import fun.asgc.neutrino.core.annotation.NonIntercept; import fun.asgc.neutrino.core.constant.MetaDataConstant; import fun.asgc.neutrino.core.context.ApplicationConfig; import fun.asgc.neutrino.core.util.*; +import fun.asgc.neutrino.core.web.annotation.RequestBody; +import fun.asgc.neutrino.core.web.annotation.RequestParam; import fun.asgc.neutrino.core.web.param.HttpContextHolder; import fun.asgc.neutrino.core.web.param.HttpRequestParser; import fun.asgc.neutrino.core.web.router.DefaultHttpRouter; @@ -41,6 +43,9 @@ import io.netty.handler.codec.http.*; import lombok.extern.slf4j.Slf4j; import org.checkerframework.checker.units.qual.C; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.util.Date; /** @@ -73,9 +78,9 @@ public class HttpRequestHandler { } if (HttpRouterType.METHOD == httpRouteResult.getType()) { try { - Object invokeResult = httpRouteResult.getMethod().invoke(httpRouteResult.getInstance()); + Object invokeResult = invoke(httpRouteResult.getInstance(), httpRouteResult.getMethod()); String res = String.valueOf(invokeResult); - if (!TypeUtil.isNormalBasicType(invokeResult.getClass())) { + if (null != invokeResult && !TypeUtil.isNormalBasicType(invokeResult.getClass())) { res = JSONObject.toJSONString(invokeResult); } FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(res.getBytes())); @@ -109,6 +114,44 @@ public class HttpRequestHandler { } } + private Object invoke(Object instance, Method method) throws InvocationTargetException, IllegalAccessException { + Object[] params = new Object[method.getParameterCount()]; + if (method.getParameterCount() > 0) { + for (int i = 0; i < method.getParameters().length; i++) { + Parameter parameter = method.getParameters()[i]; + if (FullHttpRequest.class.isAssignableFrom(parameter.getType())) { + params[i] = HttpContextHolder.getFullHttpRequest(); + } else if (HttpRequestParser.class.isAssignableFrom(parameter.getType())) { + params[i] = HttpContextHolder.getHttpRequestParser(); + } else if (ChannelHandlerContext.class.isAssignableFrom(parameter.getType())) { + params[i] = HttpContextHolder.getChannelHandlerContext(); + } else if (parameter.isAnnotationPresent(RequestBody.class)) { + String bodyString = HttpContextHolder.getHttpRequestParser().getContentAsString(); + if (TypeUtil.isNormalBasicType(parameter.getType())) { + params[i] = TypeUtil.conversion(bodyString, parameter.getType()); + } + // TODO 实体转换 + } else if (parameter.isAnnotationPresent(RequestParam.class)) { + RequestParam requestParam = parameter.getAnnotation(RequestParam.class); + if (StringUtil.isEmpty(requestParam.value())) { + throw new RuntimeException(String.format("类:%s 方法:%s @RequestParam必须指定参数名称" )); + } + String val = HttpContextHolder.getHttpRequestParser().getParameter(requestParam.value()); + if (StringUtil.isEmpty(val)) { + if (requestParam.required()) { + throw new RuntimeException(String.format("类:%s 方法:%s 参数:%s 未指定" )); + } + params[i] = null; + } else { + params[i] = TypeUtil.conversion(val, parameter.getType()); + } + } + } + } + Object invokeResult = method.invoke(instance, params); + return invokeResult; + } + private void release() { HttpContextHolder.remove(); } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/annotation/RequestBody.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/annotation/RequestBody.java new file mode 100644 index 00000000..6fba2dfd --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/annotation/RequestBody.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.web.annotation; + +import java.lang.annotation.*; + +/** + * + * @author: aoshiguchen + * @date: 2022/7/23 + */ +@Target({ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RequestBody { + boolean required() default true; +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/annotation/RequestParam.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/annotation/RequestParam.java new file mode 100644 index 00000000..425c0fe0 --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/annotation/RequestParam.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.web.annotation; + +import java.lang.annotation.*; + +/** + * + * @author: aoshiguchen + * @date: 2022/7/23 + */ +@Target({ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RequestParam { + String value() default ""; + boolean required() default true; +} diff --git a/neutrino-core/src/test/java/fun/asgc/neutrino/core/util/ClassUtilTest.java b/neutrino-core/src/test/java/fun/asgc/neutrino/core/util/ClassUtilTest.java index e8cd1a71..b8dc4f12 100644 --- a/neutrino-core/src/test/java/fun/asgc/neutrino/core/util/ClassUtilTest.java +++ b/neutrino-core/src/test/java/fun/asgc/neutrino/core/util/ClassUtilTest.java @@ -23,6 +23,8 @@ package fun.asgc.neutrino.core.util; import org.junit.Test; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -46,4 +48,27 @@ public class ClassUtilTest { } + @Test + public void test1() throws InvocationTargetException, IllegalAccessException { + Method method = ReflectUtil.getMethods(Student.class).stream().filter(m -> m.getName().equals("say")).findFirst().get(); + Student student = new Student(); + method.invoke(student, new Object[]{"1", "2"}); + } + + @Test + public void test2() throws InvocationTargetException, IllegalAccessException { + Method method = ReflectUtil.getMethods(Student.class).stream().filter(m -> m.getName().equals("hello")).findFirst().get(); + Student student = new Student(); + method.invoke(student, new Object[0]); + } + + public static class Student { + public void say(String msg1, String msg2) { + System.out.println("msg1:" + msg1 + " msg2:" + msg2); + } + public void hello() { + System.out.println("hello"); + } + } + } diff --git a/neutrino-core/src/test/java/fun/asgc/neutrino/core/web/test1/TestController.java b/neutrino-core/src/test/java/fun/asgc/neutrino/core/web/test1/TestController.java index 776e8624..cf3fd1e9 100644 --- a/neutrino-core/src/test/java/fun/asgc/neutrino/core/web/test1/TestController.java +++ b/neutrino-core/src/test/java/fun/asgc/neutrino/core/web/test1/TestController.java @@ -24,14 +24,21 @@ package fun.asgc.neutrino.core.web.test1; import fun.asgc.neutrino.core.annotation.Autowired; import fun.asgc.neutrino.core.web.annotation.GetMapping; import fun.asgc.neutrino.core.web.annotation.RequestMapping; +import fun.asgc.neutrino.core.web.annotation.RequestParam; import fun.asgc.neutrino.core.web.annotation.RestController; import fun.asgc.neutrino.core.web.param.HttpContextHolder; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.*; +import lombok.extern.slf4j.Slf4j; /** * * @author: aoshiguchen * @date: 2022/7/23 */ +@Slf4j @RestController @RequestMapping("/test1") public class TestController { @@ -43,4 +50,17 @@ public class TestController { System.out.println("拿到参数 a = " + HttpContextHolder.getHttpRequestParser().getParameterForInteger("a")); return testService.hello(); } + + @GetMapping("add") + public Integer add(@RequestParam("x") int x, @RequestParam("y") int y) { + log.info("另一种取参方式 msg:{}", HttpContextHolder.getHttpRequestParser().getParameterForString("msg")); + return x + y; + } + + @GetMapping("hello2") + public void hello2(ChannelHandlerContext context) { + FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer("aoshiguchen".getBytes())); + fullHttpResponse.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON); + context.writeAndFlush(fullHttpResponse).addListener(ChannelFutureListener.CLOSE); + } }