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

Support dynamic url #151

Merged
merged 3 commits into from
Sep 19, 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
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 @@
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);

Check warning on line 153 in cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java

View check run for this annotation

Codecov / codecov/patch

cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java#L153

Added line #L153 was not covered by tests
SendMsgReqVO vo = new SendMsgReqVO(cimUserInfo.getUserName() + ":" + groupReqVO.getMsg(), groupReqVO.getUserId());
serverApi.sendMsg(vo);
serverApi.sendMsg(vo, url);

Check warning on line 155 in cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java

View check run for this annotation

Codecov / codecov/patch

cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java#L155

Added line #L155 was not covered by tests
}

@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