diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/DynamicUrl.java b/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/DynamicUrl.java new file mode 100644 index 00000000..22e5f768 --- /dev/null +++ b/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/DynamicUrl.java @@ -0,0 +1,15 @@ +package com.crossoverjie.cim.common.core.proxy; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author crossoverJie + */ +@Target({ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface DynamicUrl { + boolean useMethodEndpoint() default true; +} diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManager.java b/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManager.java index c9406ef7..ce9323a8 100644 --- a/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManager.java +++ b/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManager.java @@ -3,17 +3,16 @@ import static com.crossoverjie.cim.common.enums.StatusEnum.VALIDATION_FAIL; import com.alibaba.fastjson.JSONObject; import com.crossoverjie.cim.common.exception.CIMException; -import com.crossoverjie.cim.common.res.BaseResponse; import com.crossoverjie.cim.common.util.HttpClient; import com.crossoverjie.cim.common.util.StringUtil; import com.fasterxml.jackson.databind.ObjectMapper; +import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Proxy; import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; import java.net.URI; import lombok.extern.slf4j.Slf4j; import okhttp3.OkHttpClient; @@ -46,6 +45,10 @@ private RpcProxyManager(Class clazz, String url, OkHttpClient okHttpClient) { this.okHttpClient = okHttpClient; } + private RpcProxyManager(Class clazz, OkHttpClient okHttpClient) { + this(clazz, "", okHttpClient); + } + /** * Default private constructor. */ @@ -65,6 +68,10 @@ public static T create(Class clazz, String url, OkHttpClient okHttpClient return new RpcProxyManager<>(clazz, url, okHttpClient).getInstance(); } + public static T create(Class clazz, OkHttpClient okHttpClient) { + return new RpcProxyManager<>(clazz, okHttpClient).getInstance(); + } + /** * Gets the proxy instance of the API. * @@ -99,26 +106,47 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl if (annotation != null && StringUtil.isNotEmpty(annotation.url())) { serverUrl = url + "/" + annotation.url(); } + URI serverUri = new URI(serverUrl); + serverUrl = serverUri.normalize().toString(); + + Object para = null; + Class parameterType = null; + for (int i = 0; i < method.getParameterAnnotations().length; i++) { + Annotation[] annotations = method.getParameterAnnotations()[i]; + if (annotations.length == 0) { + para = args[i]; + parameterType = method.getParameterTypes()[i]; + } + + for (Annotation ann : annotations) { + if (ann instanceof DynamicUrl) { + if (args[i] instanceof String) { + serverUrl = (String) args[i]; + if (((DynamicUrl) ann).useMethodEndpoint()) { + serverUrl = serverUrl + "/" + method.getName(); + } + break; + } else { + throw new CIMException("DynamicUrl must be String type"); + } + } + } + } + try { if (annotation != null && annotation.method().equals(Request.GET)) { result = HttpClient.get(okHttpClient, serverUrl); } else { - JSONObject jsonObject = new JSONObject(); - URI serverUri = new URI(serverUrl); - serverUrl = serverUri.normalize().toString(); - if (args != null && args.length > 1) { + if (args == null || args.length > 2 || para == null || parameterType == null) { throw new IllegalArgumentException(VALIDATION_FAIL.message()); } - - if (method.getParameterTypes().length > 0) { - Object para = args[0]; - Class parameterType = method.getParameterTypes()[0]; - for (Field field : parameterType.getDeclaredFields()) { - field.setAccessible(true); - jsonObject.put(field.getName(), field.get(para)); - } + JSONObject jsonObject = new JSONObject(); + for (Field field : parameterType.getDeclaredFields()) { + field.setAccessible(true); + jsonObject.put(field.getName(), field.get(para)); } + result = HttpClient.post(okHttpClient, jsonObject.toString(), serverUrl); } if (method.getReturnType() == void.class) { @@ -131,7 +159,8 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl return objectMapper.readValue(json, method.getReturnType()); } else { return objectMapper.readValue(json, objectMapper.getTypeFactory() - .constructParametricType(method.getReturnType(), objectMapper.getTypeFactory().constructType(genericTypeOfBaseResponse))); + .constructParametricType(method.getReturnType(), + objectMapper.getTypeFactory().constructType(genericTypeOfBaseResponse))); } } finally { if (result != null) { @@ -166,35 +195,35 @@ private Type getGenericTypeOfBaseResponse(Method declaredMethod) { * @throws ClassNotFoundException if the class of the generic type is not found private Class getBaseResponseGeneric(Method declaredMethod) throws ClassNotFoundException { - Type returnType = declaredMethod.getGenericReturnType(); + Type returnType = declaredMethod.getGenericReturnType(); - // check if the return type is a parameterized type - if (returnType instanceof ParameterizedType parameterizedType) { + // check if the return type is a parameterized type + if (returnType instanceof ParameterizedType parameterizedType) { - Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); - for (Type typeArgument : actualTypeArguments) { - // BaseResponse only has one generic type - return getClass(typeArgument); - } - } + for (Type typeArgument : actualTypeArguments) { + // BaseResponse only has one generic type + return getClass(typeArgument); + } + } - return null; + return null; } public static Class getClass(Type type) throws ClassNotFoundException { - if (type instanceof Class) { - // 普通类型,直接返回 - return (Class) type; - } else if (type instanceof ParameterizedType) { - // 参数化类型,返回原始类型 - return getClass(((ParameterizedType) type).getRawType()); - } else if (type instanceof TypeVariable) { - // 类型变量,无法在运行时获取具体类型 - return Object.class; - } else { - throw new ClassNotFoundException("无法处理的类型: " + type.toString()); - } + if (type instanceof Class) { + // 普通类型,直接返回 + return (Class) type; + } else if (type instanceof ParameterizedType) { + // 参数化类型,返回原始类型 + return getClass(((ParameterizedType) type).getRawType()); + } else if (type instanceof TypeVariable) { + // 类型变量,无法在运行时获取具体类型 + return Object.class; + } else { + throw new ClassNotFoundException("无法处理的类型: " + type.toString()); + } }*/ } \ No newline at end of file diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManagerTest.java b/cim-common/src/test/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManagerTest.java index 834b90e5..c1c43c02 100644 --- a/cim-common/src/test/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManagerTest.java +++ b/cim-common/src/test/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManagerTest.java @@ -1,5 +1,6 @@ package com.crossoverjie.cim.common.core.proxy; +import com.crossoverjie.cim.common.exception.CIMException; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import java.io.Serializable; @@ -38,6 +39,30 @@ public void testPost() { Assertions.assertEquals(response.getParsedBody().getCity(), "shenzhen"); } + @Test + public void testUrl() { + OkHttpClient client = new OkHttpClient(); + String url = "http://echo.free.beeceptor.com/sample-request?author=beeceptor"; + Echo echo = RpcProxyManager.create(Echo.class, client); + EchoRequest request = new EchoRequest(); + request.setName("crossoverJie"); + request.setAge(18); + request.setCity("shenzhen"); + EchoResponse response = echo.echoTarget(url,request); + Assertions.assertEquals(response.getParsedBody().getName(), "crossoverJie"); + Assertions.assertEquals(response.getParsedBody().getAge(), 18); + Assertions.assertEquals(response.getParsedBody().getCity(), "shenzhen"); + response = echo.echoTarget(request, url); + Assertions.assertEquals(response.getParsedBody().getName(), "crossoverJie"); + + String req = "/request"; + response = echo.request("http://echo.free.beeceptor.com", request); + Assertions.assertEquals(response.getPath(), req); + Assertions.assertEquals(response.getParsedBody().getAge(), 18); + + Assertions.assertThrows(CIMException.class, () -> echo.echoTarget(request)); + } + @Test public void testFail() { OkHttpClient client = new OkHttpClient(); @@ -47,7 +72,7 @@ public void testFail() { request.setName("crossoverJie"); request.setAge(18); request.setCity("shenzhen"); - Assertions.assertThrows(IllegalArgumentException.class, () -> echo.fail(request, "test")); + Assertions.assertThrows(IllegalArgumentException.class, () -> echo.fail(request, "test","")); } @@ -67,8 +92,15 @@ public void testGeneric() { interface Echo { @Request(url = "sample-request?author=beeceptor") EchoResponse echo(EchoRequest message); + + @Request(url = "sample-request?author=beeceptor") + EchoResponse echoTarget(@DynamicUrl(useMethodEndpoint = false) String url, EchoRequest message); + EchoResponse echoTarget(EchoRequest message, @DynamicUrl(useMethodEndpoint = false) String url); + @Request(url = "sample-request?author=beeceptor") + EchoResponse echoTarget(@DynamicUrl EchoRequest message); + EchoResponse request(@DynamicUrl() String url, EchoRequest message); @Request(url = "sample-request?author=beeceptor") - EchoResponse fail(EchoRequest message, String s); + EchoResponse fail(EchoRequest message, String s, String s1); @Request(url = "sample-request?author=beeceptor") EchoGeneric echoGeneric(EchoRequest message); diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java index 4b10699c..24bcde91 100644 --- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java +++ b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java @@ -150,9 +150,9 @@ public void pushMsg(CIMServerResVO cimServerResVO, long sendUserId, ChatReqVO gr CIMUserInfo cimUserInfo = userInfoCacheService.loadUserInfoByUserId(sendUserId); String url = "http://" + cimServerResVO.getIp() + ":" + cimServerResVO.getHttpPort(); - ServerApi serverApi = RpcProxyManager.create(ServerApi.class, url, okHttpClient); + ServerApi serverApi = RpcProxyManager.create(ServerApi.class, okHttpClient); SendMsgReqVO vo = new SendMsgReqVO(cimUserInfo.getUserName() + ":" + groupReqVO.getMsg(), groupReqVO.getUserId()); - serverApi.sendMsg(vo); + serverApi.sendMsg(vo, url); } @Override diff --git a/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/ServerApi.java b/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/ServerApi.java index b36d3857..4e459cb7 100644 --- a/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/ServerApi.java +++ b/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/ServerApi.java @@ -1,5 +1,6 @@ package com.crossoverjie.cim.server.api; +import com.crossoverjie.cim.common.core.proxy.DynamicUrl; import com.crossoverjie.cim.common.res.BaseResponse; import com.crossoverjie.cim.server.api.vo.req.SendMsgReqVO; import com.crossoverjie.cim.server.api.vo.res.SendMsgResVO; @@ -19,5 +20,5 @@ public interface ServerApi { * @return * @throws Exception */ - BaseResponse sendMsg(SendMsgReqVO sendMsgReqVO) throws Exception; + BaseResponse sendMsg(SendMsgReqVO sendMsgReqVO, @DynamicUrl String url) throws Exception; } diff --git a/cim-server/src/main/java/com/crossoverjie/cim/server/controller/IndexController.java b/cim-server/src/main/java/com/crossoverjie/cim/server/controller/IndexController.java index a85b8677..748e46fa 100644 --- a/cim-server/src/main/java/com/crossoverjie/cim/server/controller/IndexController.java +++ b/cim-server/src/main/java/com/crossoverjie/cim/server/controller/IndexController.java @@ -1,5 +1,6 @@ package com.crossoverjie.cim.server.controller; +import com.crossoverjie.cim.common.core.proxy.DynamicUrl; import com.crossoverjie.cim.common.enums.StatusEnum; import com.crossoverjie.cim.common.res.BaseResponse; import com.crossoverjie.cim.server.api.ServerApi; @@ -38,7 +39,7 @@ public class IndexController implements ServerApi { @Operation(summary = "Push msg to client") @RequestMapping(value = "sendMsg",method = RequestMethod.POST) @ResponseBody - public BaseResponse sendMsg(@RequestBody SendMsgReqVO sendMsgReqVO){ + public BaseResponse sendMsg(@RequestBody SendMsgReqVO sendMsgReqVO, @DynamicUrl String url){ BaseResponse res = new BaseResponse(); cimServer.sendMsg(sendMsgReqVO) ;