From 02f86f93d2ea61f65108e6ac7c583285b8bbcd52 Mon Sep 17 00:00:00 2001 From: zhangzhiyong Date: Mon, 27 Nov 2023 11:48:02 +0800 Subject: [PATCH 1/3] update --- .../openai/src/main/java/run/mone/openai/OpenaiCall.java | 2 +- .../src/test/java/run/mone/openapi/OpenApiTest.java | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/jcommon/openai/src/main/java/run/mone/openai/OpenaiCall.java b/jcommon/openai/src/main/java/run/mone/openai/OpenaiCall.java index 2c65952ee..8f4fafa1d 100644 --- a/jcommon/openai/src/main/java/run/mone/openai/OpenaiCall.java +++ b/jcommon/openai/src/main/java/run/mone/openai/OpenaiCall.java @@ -265,7 +265,7 @@ public void onClosed(EventSource eventSource) { @Override public void onFailure(EventSource eventSource, @Nullable Throwable t, @Nullable Response response) { - log.error("on failure error:" + t, t); + log.error("on failure error:" + response, t); } }); } diff --git a/jcommon/openai/src/test/java/run/mone/openapi/OpenApiTest.java b/jcommon/openai/src/test/java/run/mone/openapi/OpenApiTest.java index c37f33d55..1c25e6a22 100644 --- a/jcommon/openai/src/test/java/run/mone/openapi/OpenApiTest.java +++ b/jcommon/openai/src/test/java/run/mone/openapi/OpenApiTest.java @@ -26,6 +26,7 @@ import io.reactivex.disposables.Disposable; import lombok.Data; import lombok.SneakyThrows; +import okhttp3.Response; import okhttp3.logging.HttpLoggingInterceptor; import okhttp3.sse.EventSource; import okhttp3.sse.EventSourceListener; @@ -168,7 +169,7 @@ private OpenAiClient client() { public void testCallStream() { String key = System.getenv("open_api_key"); CountDownLatch latch = new CountDownLatch(1); - OpenaiCall.callStream(key, null, "天空为什么是蓝色的", new String[]{}, new StreamListener() { + OpenaiCall.callStream(key, "", "天空为什么是蓝色的", new String[]{}, new StreamListener() { @Override public void onEvent(String str) { System.out.println(str); @@ -178,6 +179,11 @@ public void onEvent(String str) { public void end() { latch.countDown(); } + + @Override + public void onFailure(Throwable t, Response response) { + System.out.println(t + "" + response); + } }); latch.await(); } From e1f628c04358ec4448d6ca98a88bde8e04922964 Mon Sep 17 00:00:00 2001 From: zhangzhiyong Date: Sat, 24 Feb 2024 14:48:04 +0800 Subject: [PATCH 2/3] Support for static file parsing has been added --- jcommon/docean/pom.xml | 4 +-- .../java/com/xiaomi/youpin/docean/Mvc.java | 4 +++ .../xiaomi/youpin/docean/bo/MvcConfig.java | 4 +++ .../docean/config/HttpServerConfig.java | 3 +- .../xiaomi/youpin/docean/mvc/MvcRunnable.java | 30 +++++++++++++--- .../youpin/docean/mvc/common/MvcConst.java | 6 ++++ .../xiaomi/youpin/docean/mvc/html/Html.java | 35 +++++++++++++++++++ .../youpin/docean/test/HttpServerTest.java | 6 ++-- .../src/test/resources/config.properties | 4 +++ 9 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/html/Html.java diff --git a/jcommon/docean/pom.xml b/jcommon/docean/pom.xml index 5e4621c9e..af119859a 100644 --- a/jcommon/docean/pom.xml +++ b/jcommon/docean/pom.xml @@ -16,8 +16,8 @@ run.mone easy - - 1.5.0-jdk21 + 1.4-jdk21-SNAPSHOT + cglib diff --git a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/Mvc.java b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/Mvc.java index d6cd74510..df8f4804f 100644 --- a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/Mvc.java +++ b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/Mvc.java @@ -78,6 +78,10 @@ private void setConfig(Ioc ioc) { this.mvcConfig.setAllowCross(Boolean.valueOf(ioc.getBean(MvcConst.ALLOW_CROSS_DOMAIN, MvcConst.FALSE))); this.mvcConfig.setDownload(Boolean.valueOf(ioc.getBean(MvcConst.MVC_DOWNLOAD, MvcConst.FALSE))); this.mvcConfig.setUseCglib(Boolean.valueOf(ioc.getBean(MvcConst.CGLIB, MvcConst.TRUE))); + + this.mvcConfig.setOpenStaticFile(Boolean.valueOf(ioc.getBean(MvcConst.OPEN_STATIC_FILE, MvcConst.FALSE))); + this.mvcConfig.setStaticFilePath(ioc.getBean(MvcConst.STATIC_FILE_PATH, MvcConst.EMPTY)); + this.mvcConfig.setResponseOriginalValue(Boolean.valueOf(ioc.getBean(MvcConst.RESPONSE_ORIGINAL_VALUE, MvcConst.FALSE))); this.mvcConfig.setPoolSize(Integer.valueOf(ioc.getBean(MvcConst.MVC_POOL_SIZE, String.valueOf(MvcConst.DEFAULT_MVC_POOL_SIZE)))); this.mvcConfig.setVirtualThread(Boolean.valueOf(ioc.getBean(MvcConst.VIRTUAL_THREAD, MvcConst.TRUE))); diff --git a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/bo/MvcConfig.java b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/bo/MvcConfig.java index 6159d4b91..f93e818ca 100644 --- a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/bo/MvcConfig.java +++ b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/bo/MvcConfig.java @@ -38,4 +38,8 @@ public class MvcConfig implements Serializable { */ private boolean virtualThread; + private String staticFilePath; + + private boolean openStaticFile; + } diff --git a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/config/HttpServerConfig.java b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/config/HttpServerConfig.java index 904a0ee18..2b8780eb5 100644 --- a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/config/HttpServerConfig.java +++ b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/config/HttpServerConfig.java @@ -52,10 +52,9 @@ public class HttpServerConfig { private boolean userWs; - public static int HTTP_POOL_SIZE = 500; - public static int HTTP_POOL_QUEUE_SIZE = 1000; + public static int HTTP_POOL_QUEUE_SIZE = 1000; public enum HttpVersion { http1, http2 diff --git a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/MvcRunnable.java b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/MvcRunnable.java index 20a94e674..ea1ebdd13 100644 --- a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/MvcRunnable.java +++ b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/MvcRunnable.java @@ -2,11 +2,14 @@ import com.google.gson.Gson; import com.xiaomi.youpin.docean.Mvc; +import com.xiaomi.youpin.docean.bo.MvcConfig; import com.xiaomi.youpin.docean.common.Cons; import com.xiaomi.youpin.docean.common.Safe; +import com.xiaomi.youpin.docean.common.StringUtils; import com.xiaomi.youpin.docean.config.HttpServerConfig; import com.xiaomi.youpin.docean.mvc.common.MvcConst; import com.xiaomi.youpin.docean.mvc.download.Download; +import com.xiaomi.youpin.docean.mvc.html.Html; import com.xiaomi.youpin.docean.mvc.upload.MvcUpload; import com.xiaomi.youpin.docean.mvc.util.ExceptionUtil; import com.xiaomi.youpin.docean.mvc.util.MethodFinder; @@ -31,6 +34,8 @@ public class MvcRunnable implements Runnable { private MvcResponse response; + private MvcConfig config; + private ConcurrentHashMap requestMethodMap; private Mvc mvc; @@ -43,6 +48,7 @@ public MvcRunnable(Mvc mvc, MvcContext context, MvcRequest request, MvcResponse this.response = response; this.requestMethodMap = requestMethodMap; this.mvc = mvc; + this.config = this.mvc.getMvcConfig(); } @@ -65,6 +71,7 @@ public MvcRunnable(Mvc mvc, HttpServerConfig config, ChannelHandlerContext ctx, this.request.setBody(body); this.response.setCtx(ctx); this.mvc = mvc; + this.config = this.mvc.getMvcConfig(); this.requestMethodMap = requestMethodMap; } @@ -107,6 +114,17 @@ private void call() { } String path = request.getPath(); + + if (config.isOpenStaticFile() && Html.isHtmlFile(path)) { + String content = Html.view(config.getStaticFilePath() + path); + if (StringUtils.isEmpty(content)) { + sendNotFoundResponse(); + return; + } + response.writeAndFlush(context, content); + return; + } + //Support file download (/download) and must enable downloads. if (isDownload(path) && mvc.getMvcConfig().isDownload()) { Download.download(context, request, response); @@ -127,16 +145,20 @@ private void call() { } if (!path.equals(Cons.Service)) { - MvcResult result = new MvcResult<>(); - result.setCode(HttpResponseStatus.NOT_FOUND.code()); - result.setMessage(HttpResponseStatus.NOT_FOUND.reasonPhrase()); - response.writeAndFlush(context, gson.toJson(result)); + sendNotFoundResponse(); return; } //rate limited or exceeded quota mvc.callService(context, request, response); } + private void sendNotFoundResponse() { + MvcResult result = new MvcResult<>(); + result.setCode(HttpResponseStatus.NOT_FOUND.code()); + result.setMessage(HttpResponseStatus.NOT_FOUND.reasonPhrase()); + response.writeAndFlush(context, gson.toJson(result)); + } + private boolean isDownload(String path) { return path.equals("/download"); diff --git a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/common/MvcConst.java b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/common/MvcConst.java index 0d01c175d..d2538ee71 100644 --- a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/common/MvcConst.java +++ b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/common/MvcConst.java @@ -10,8 +10,14 @@ public abstract class MvcConst { public static final String CGLIB = "$cglib"; + public static final String STATIC_FILE_PATH = "$staticFilePath"; + + public static final String OPEN_STATIC_FILE = "$openStaticFile"; + public static final String TRUE = "true"; + public static final String EMPTY = ""; + public static final String FALSE = "false"; public static final String ALLOW_CROSS_DOMAIN = "$allow-cross-domain"; diff --git a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/html/Html.java b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/html/Html.java new file mode 100644 index 000000000..6f57e96e6 --- /dev/null +++ b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/html/Html.java @@ -0,0 +1,35 @@ +package com.xiaomi.youpin.docean.mvc.html; + +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * @author goodjava@qq.com + * @date 2024/2/24 14:10 + */ +@Slf4j +public class Html { + + //读取指定html页面文件内容并返回 + public static String view(String file) { + try { + Path path = Paths.get(file); + return new String(Files.readAllBytes(path), StandardCharsets.UTF_8); + } catch (IOException e) { + log.error(e.getMessage(), e); + e.printStackTrace(); + return ""; + } + } + + //判断一个文件是否是.html文件,并且返回boolean值(class) + public static boolean isHtmlFile(String filePath) { + return filePath != null && filePath.toLowerCase().endsWith(".html"); + } + +} diff --git a/jcommon/docean/src/test/java/com/xiaomi/youpin/docean/test/HttpServerTest.java b/jcommon/docean/src/test/java/com/xiaomi/youpin/docean/test/HttpServerTest.java index 00b677105..4c7fd66e0 100644 --- a/jcommon/docean/src/test/java/com/xiaomi/youpin/docean/test/HttpServerTest.java +++ b/jcommon/docean/src/test/java/com/xiaomi/youpin/docean/test/HttpServerTest.java @@ -79,7 +79,7 @@ public void testHttpServer() throws InterruptedException { } - Ioc.ins().putBean("$response-original-value", "true"); + Ioc.ins().putBean("$response-original-value", "true").putBean("$openStaticFile","true").putBean("$staticFilePath","/tmp/"); // Ioc.ins().putBean("$ssl_domain", "zzy.com"); // Ioc.ins().putBean("$ssl_self_sign", "false"); // Ioc.ins().putBean("$ssl_certificate","/Users/zhangzhiyong/key/zzy.com/certificate.crt"); @@ -88,8 +88,8 @@ public void testHttpServer() throws InterruptedException { Mvc.ins(); DoceanHttpServer server = new DoceanHttpServer(HttpServerConfig.builder() .httpVersion(HttpServerConfig.HttpVersion.http1) -// .ssl(true) - .port(8999) + .ssl(false) + .port(8899) .websocket(false) .uploadDir("/tmp/v").upload(false) .build()); diff --git a/jcommon/docean/src/test/resources/config.properties b/jcommon/docean/src/test/resources/config.properties index cc623e74e..a4c52ffe1 100644 --- a/jcommon/docean/src/test/resources/config.properties +++ b/jcommon/docean/src/test/resources/config.properties @@ -9,4 +9,8 @@ demoVo=com.xiaomi.youpin.docean.test.demo.DemoVo val=123 +openStaticFile=true +staticFilePath=/tmp/ + + From bbbf3d625a8f28711a582fc084efed713197d2c0 Mon Sep 17 00:00:00 2001 From: zhangzhiyong Date: Tue, 27 Feb 2024 14:55:10 +0800 Subject: [PATCH 3/3] docean supports mvc non-JSON format single-parameter call --- .../java/com/xiaomi/youpin/docean/Mvc.java | 88 ++++++++++++------- .../xiaomi/youpin/docean/mvc/MvcRunnable.java | 5 +- .../com/xiaomi/youpin/docean/mvc/Post.java | 1 - .../docean/test/demo/DemoController.java | 6 ++ 4 files changed, 68 insertions(+), 32 deletions(-) diff --git a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/Mvc.java b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/Mvc.java index df8f4804f..81a29df60 100644 --- a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/Mvc.java +++ b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/Mvc.java @@ -31,6 +31,7 @@ import com.xiaomi.youpin.docean.mvc.*; import com.xiaomi.youpin.docean.mvc.common.MvcConst; import com.xiaomi.youpin.docean.mvc.util.ExceptionUtil; +import com.xiaomi.youpin.docean.mvc.util.GsonUtils; import com.xiaomi.youpin.docean.mvc.util.Jump; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.FullHttpRequest; @@ -100,33 +101,41 @@ private void initHttpRequestMethod() { ioc.beans().entrySet().stream().forEach(entry -> { Bean bean = entry.getValue(); if (bean.getType() == Bean.Type.controller.ordinal()) { - Arrays.stream(bean.getClazz().getMethods()).forEach(m -> Optional.ofNullable(m.getAnnotation(RequestMapping.class)).ifPresent(rm -> { - String path = rm.path(); - HttpRequestMethod hrm = new HttpRequestMethod(); - hrm.setTimeout(rm.timeout()); - hrm.setPath(path); - hrm.setObj(bean.getObj()); - hrm.setMethod(m); - hrm.setHttpMethod(rm.method()); - ioc.publishEvent(new Event(EventType.initController, path)); - requestMethodMap.put(path, hrm); - })); + registerControllerMethods(bean); } if (bean.getObj() instanceof MvcServlet) { - MvcServlet ms = (MvcServlet) bean.getObj(); - String path = ms.path(); - HttpRequestMethod hrm = new HttpRequestMethod(); - hrm.setPath(path); - hrm.setObj(ms); - hrm.setHttpMethod(ms.method()); - Safe.runAndLog(() -> hrm.setMethod(ms.getClass().getMethod("execute", Object.class))); - ioc.publishEvent(new Event(EventType.initController, path)); - requestMethodMap.put(path, hrm); + initializeControllerMapping(bean); } }); log.info("requestMethodMap size:{}", this.requestMethodMap.size()); } + private void initializeControllerMapping(Bean bean) { + MvcServlet ms = (MvcServlet) bean.getObj(); + String path = ms.path(); + HttpRequestMethod hrm = new HttpRequestMethod(); + hrm.setPath(path); + hrm.setObj(ms); + hrm.setHttpMethod(ms.method()); + Safe.runAndLog(() -> hrm.setMethod(ms.getClass().getMethod("execute", Object.class))); + ioc.publishEvent(new Event(EventType.initController, path)); + requestMethodMap.put(path, hrm); + } + + private void registerControllerMethods(Bean bean) { + Arrays.stream(bean.getClazz().getMethods()).forEach(m -> Optional.ofNullable(m.getAnnotation(RequestMapping.class)).ifPresent(rm -> { + String path = rm.path(); + HttpRequestMethod hrm = new HttpRequestMethod(); + hrm.setTimeout(rm.timeout()); + hrm.setPath(path); + hrm.setObj(bean.getObj()); + hrm.setMethod(m); + hrm.setHttpMethod(rm.method()); + ioc.publishEvent(new Event(EventType.initController, path)); + requestMethodMap.put(path, hrm); + })); + } + private static final class LazyHolder { private static final Mvc ins = new Mvc(Ioc.ins()); @@ -173,20 +182,25 @@ public void callService(MvcContext context, MvcRequest request, MvcResponse resp public void callMethod(MvcContext context, MvcRequest request, MvcResponse response, MvcResult result, HttpRequestMethod method) { Safe.run(() -> { - JsonElement args = getArgs(method, request.getMethod().toLowerCase(Locale.ROOT), request, context); Object[] params = new Object[]{null}; - if (method.getMethod().getParameterTypes().length == 1 && method.getMethod().getParameterTypes()[0].equals(MvcContext.class)) { - params[0] = context; + //If there is only one parameter and it is a String, no further parsing is necessary; it can be used directly. + if (isSingleStringParameterMethod(method)) { + params[0] = new String(request.getBody()); } else { - try { - params = methodInvoker.getMethodParams(method.getMethod(), args); - } catch (Exception e) { - log.error("getMethodParams error,path:{},params:{},method:{}", context.getPath(), - new Gson().toJson(context.getParams()), request.getMethod().toLowerCase(Locale.ROOT), e); + JsonElement args = getArgs(method, request.getMethod().toLowerCase(Locale.ROOT), request, context); + if (isSingleMvcContextParameterMethod(method)) { + params[0] = context; + } else { + try { + params = methodInvoker.getMethodParams(method.getMethod(), args); + } catch (Exception e) { + log.error("getMethodParams error,path:{},params:{},method:{}", context.getPath(), + GsonUtils.gson.toJson(context.getParams()), request.getMethod().toLowerCase(Locale.ROOT), e); + } } } - Object data = this.mvcConfig.isUseCglib() ? methodInvoker.invokeFastMethod(method.getObj(), method.getMethod(), params) : - methodInvoker.invokeMethod(method.getObj(), method.getMethod(), params); + + Object data = invokeControllerMethod(method, params); if (context.isSync()) { context.setResponse(data); @@ -234,6 +248,20 @@ public void callMethod(MvcContext context, MvcRequest request, MvcResponse respo }); } + private Object invokeControllerMethod(HttpRequestMethod method, Object[] params) { + Object data = this.mvcConfig.isUseCglib() ? methodInvoker.invokeFastMethod(method.getObj(), method.getMethod(), params) : + methodInvoker.invokeMethod(method.getObj(), method.getMethod(), params); + return data; + } + + private static boolean isSingleMvcContextParameterMethod(HttpRequestMethod method) { + return method.getMethod().getParameterTypes().length == 1 && method.getMethod().getParameterTypes()[0].equals(MvcContext.class); + } + + private static boolean isSingleStringParameterMethod(HttpRequestMethod method) { + return method.getMethod().getParameterTypes().length == 1 && method.getMethod().getParameterTypes()[0].equals(String.class); + } + /** * parsing parameters * diff --git a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/MvcRunnable.java b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/MvcRunnable.java index ea1ebdd13..917841de1 100644 --- a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/MvcRunnable.java +++ b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/MvcRunnable.java @@ -12,6 +12,7 @@ import com.xiaomi.youpin.docean.mvc.html.Html; import com.xiaomi.youpin.docean.mvc.upload.MvcUpload; import com.xiaomi.youpin.docean.mvc.util.ExceptionUtil; +import com.xiaomi.youpin.docean.mvc.util.GsonUtils; import com.xiaomi.youpin.docean.mvc.util.MethodFinder; import com.xiaomi.youpin.docean.mvc.util.RequestUtils; import io.netty.channel.ChannelHandlerContext; @@ -105,8 +106,9 @@ private void call() { if (context.isWebsocket()) { WsRequest req = new Gson().fromJson(new String(request.getBody()), WsRequest.class); request.setPath(req.getPath()); - request.setBody(new Gson().toJson(req.getParams()).getBytes()); + request.setBody(GsonUtils.gson.toJson(req.getParams()).getBytes()); } + //Directly returning not found when searching for favicon.ico. if (isFaviconIco(request)) { response.writeAndFlush(context, HttpResponseStatus.NOT_FOUND, ""); @@ -115,6 +117,7 @@ private void call() { String path = request.getPath(); + //Directly render static pages. if (config.isOpenStaticFile() && Html.isHtmlFile(path)) { String content = Html.view(config.getStaticFilePath() + path); if (StringUtils.isEmpty(content)) { diff --git a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/Post.java b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/Post.java index bd0ecbe77..09656a1a9 100644 --- a/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/Post.java +++ b/jcommon/docean/src/main/java/com/xiaomi/youpin/docean/mvc/Post.java @@ -16,7 +16,6 @@ package com.xiaomi.youpin.docean.mvc; -import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.xiaomi.youpin.docean.mvc.httpmethod.HttpMethodUtils; diff --git a/jcommon/docean/src/test/java/com/xiaomi/youpin/docean/test/demo/DemoController.java b/jcommon/docean/src/test/java/com/xiaomi/youpin/docean/test/demo/DemoController.java index 122649cab..fe68c91b7 100644 --- a/jcommon/docean/src/test/java/com/xiaomi/youpin/docean/test/demo/DemoController.java +++ b/jcommon/docean/src/test/java/com/xiaomi/youpin/docean/test/demo/DemoController.java @@ -182,6 +182,12 @@ public String testSession2(MvcContext context) { return "session:" + name; } + //Test the scenario where only a single parameter is passed, and it is of type String. + @RequestMapping(path = "/string") + public String string(String str) { + return str; + } + public void destory() { log.info("destory controller");