Skip to content

Commit

Permalink
Merge pull request #151 from crossoverJie/proxy-dynamic
Browse files Browse the repository at this point in the history
Support dynamic url
  • Loading branch information
crossoverJie authored Sep 19, 2024
2 parents 3c4f917 + 0f0d718 commit 581fbeb
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -46,6 +45,10 @@ private RpcProxyManager(Class<T> clazz, String url, OkHttpClient okHttpClient) {
this.okHttpClient = okHttpClient;
}

private RpcProxyManager(Class<T> clazz, OkHttpClient okHttpClient) {
this(clazz, "", okHttpClient);
}

/**
* Default private constructor.
*/
Expand All @@ -65,6 +68,10 @@ public static <T> T create(Class<T> clazz, String url, OkHttpClient okHttpClient
return new RpcProxyManager<>(clazz, url, okHttpClient).getInstance();
}

public static <T> T create(Class<T> clazz, OkHttpClient okHttpClient) {
return new RpcProxyManager<>(clazz, okHttpClient).getInstance();
}

/**
* Gets the proxy instance of the API.
*
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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());
}
}*/

}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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",""));
}


Expand All @@ -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<EchoResponse.HeadersDTO> echoGeneric(EchoRequest message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -19,5 +20,5 @@ public interface ServerApi {
* @return
* @throws Exception
*/
BaseResponse<SendMsgResVO> sendMsg(SendMsgReqVO sendMsgReqVO) throws Exception;
BaseResponse<SendMsgResVO> sendMsg(SendMsgReqVO sendMsgReqVO, @DynamicUrl String url) throws Exception;
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -38,7 +39,7 @@ public class IndexController implements ServerApi {
@Operation(summary = "Push msg to client")
@RequestMapping(value = "sendMsg",method = RequestMethod.POST)
@ResponseBody
public BaseResponse<SendMsgResVO> sendMsg(@RequestBody SendMsgReqVO sendMsgReqVO){
public BaseResponse<SendMsgResVO> sendMsg(@RequestBody SendMsgReqVO sendMsgReqVO, @DynamicUrl String url){
BaseResponse<SendMsgResVO> res = new BaseResponse();
cimServer.sendMsg(sendMsgReqVO) ;

Expand Down

0 comments on commit 581fbeb

Please sign in to comment.