Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docean supports mvc non-JSON format single-parameter call #794

Merged
merged 7 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions jcommon/docean/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
<dependency>
<groupId>run.mone</groupId>
<artifactId>easy</artifactId>
<!-- <version>1.4-jdk21-SNAPSHOT</version>-->
<version>1.5.0-jdk21</version>
<version>1.4-jdk21-SNAPSHOT</version>
<!-- <version>1.5.0-jdk21</version>-->
</dependency>
<dependency>
<groupId>cglib</groupId>
Expand Down
88 changes: 58 additions & 30 deletions jcommon/docean/src/main/java/com/xiaomi/youpin/docean/Mvc.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,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;
Expand Down Expand Up @@ -102,33 +103,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());
Expand Down Expand Up @@ -175,20 +184,25 @@ public void callService(MvcContext context, MvcRequest request, MvcResponse resp

public void callMethod(MvcContext context, MvcRequest request, MvcResponse response, MvcResult<Object> 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);
Expand Down Expand Up @@ -238,6 +252,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
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -105,16 +106,16 @@ 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, "");
return;
}
String path = request.getPath();


if (config.isOpenStaticFile() && Html.isHtmlFile(path)) {
String content = Html.view(config.getStaticFilePath() + path);
if (StringUtils.isEmpty(content)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Loading