From f2ff322147177822a52283f559c1a9c2c061e4f1 Mon Sep 17 00:00:00 2001 From: WenG <450292408@qq.com> Date: Sun, 19 Sep 2021 00:33:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84Rest=E8=BF=9C=E7=A8=8B?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E7=B1=BB=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rest/handler/RestRemoteHandler.java | 278 +++++++++++++++++- .../remote/rest/proxy/RestRemoteProxy.java | 18 +- .../rest/request/RestRemoteRequest.java | 14 + 3 files changed, 295 insertions(+), 15 deletions(-) create mode 100644 basic-util/src/main/java/ink/wgink/util/remote/rest/request/RestRemoteRequest.java diff --git a/basic-util/src/main/java/ink/wgink/util/remote/rest/handler/RestRemoteHandler.java b/basic-util/src/main/java/ink/wgink/util/remote/rest/handler/RestRemoteHandler.java index 7e31f3d4..c98a0f52 100644 --- a/basic-util/src/main/java/ink/wgink/util/remote/rest/handler/RestRemoteHandler.java +++ b/basic-util/src/main/java/ink/wgink/util/remote/rest/handler/RestRemoteHandler.java @@ -1,7 +1,21 @@ package ink.wgink.util.remote.rest.handler; +import ink.wgink.exceptions.ParamsException; +import ink.wgink.exceptions.base.SystemException; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @ClassName: RestRemoterHandler @@ -12,15 +26,269 @@ import java.lang.reflect.Method; */ public class RestRemoteHandler implements InvocationHandler { + private static final Pattern PATH_VARIABLE = Pattern.compile("\\{[^\\s\\}]+\\}"); + @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - System.out.println(method.getDeclaringClass().getClassLoader()); - // 否则执行统一接口处理方法 - return method.invoke(this, args); + return handle(method, args); } - public Object run() { - return "run"; + /** + * 处理 + * + * @param method + * @param args + * @return + */ + public Object handle(Method method, Object[] args) throws UnsupportedEncodingException { + Map pathVariableParams = getPathVariableParams(method.getParameters(), args); + Map queryVariableParams = getQueryVariableParams(method.getParameters(), args); + Map headerVariableParams = getHeaderVariableParams(method.getParameters(), args); + String uri; + Object requestBody = null; + RequestMethod requestMethod = null; + if (method.isAnnotationPresent(GetMapping.class)) { + // GET请求 + requestMethod = RequestMethod.GET; + GetMapping getMapping = method.getAnnotation(GetMapping.class); + uri = getMapping.value()[0]; + } else if (method.isAnnotationPresent(DeleteMapping.class)) { + // DELETE请求 + requestMethod = RequestMethod.DELETE; + DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class); + uri = deleteMapping.value()[0]; + } else if (method.isAnnotationPresent(PostMapping.class)) { + // POST请求 + requestMethod = RequestMethod.POST; + PostMapping postMapping = method.getAnnotation(PostMapping.class); + uri = postMapping.value()[0]; + requestBody = getRequestBody(method.getParameters(), args); + } else if (method.isAnnotationPresent(PutMapping.class)) { + // PUT请求 + requestMethod = RequestMethod.PUT; + PutMapping putMapping = method.getAnnotation(PutMapping.class); + uri = putMapping.value()[0]; + requestBody = getRequestBody(method.getParameters(), args); + } else { + return null; + } + List pathVariable = listPathVariables(uri); + checkPathVariables(pathVariable); + checkPathVariableParams(pathVariable, pathVariableParams); + uri = buildUri(uri, pathVariable, pathVariableParams); + uri = buildFullUri(uri, queryVariableParams); + + System.out.println("uri: " + uri); + System.out.println("requestBody: " + requestBody); + System.out.println("headerVariableParams: " + headerVariableParams); + System.out.println("requestMethod: " + requestMethod.name()); + return uri; + } + + /** + * 路径变量列表 + * + * @param uri 路径 + * @return + */ + private List listPathVariables(String uri) { + List pathVariables = new ArrayList<>(); + Matcher matcher = PATH_VARIABLE.matcher(uri); + while (matcher.find()) { + String variable = matcher.group(); + pathVariables.add(variable.substring(1, variable.length() - 1)); + } + return pathVariables; + } + + /** + * 路径参数 + * + * @param parameters + * @return + */ + private Map getPathVariableParams(Parameter[] parameters, Object[] args) throws UnsupportedEncodingException { + Map pathVariableParamsMap = new HashMap<>(); + for (int i = 0; i < parameters.length; i++) { + Parameter parameter = parameters[i]; + if (!parameter.isAnnotationPresent(PathVariable.class)) { + continue; + } + PathVariable annotation = parameter.getAnnotation(PathVariable.class); + String variableName = annotation.value(); + if (StringUtils.isBlank(variableName)) { + throw new ParamsException("参数 " + parameter.getName() + " 名称不能为空"); + } + Object arg = args[i]; + if (arg == null) { + throw new SystemException("路径参数不能为空: " + variableName); + } + pathVariableParamsMap.put(variableName, URLEncoder.encode(arg.toString(), "UTF-8")); + } + return pathVariableParamsMap; + } + + /** + * 请求参数 + * + * @param parameters + * @param args + * @return + */ + private Map getQueryVariableParams(Parameter[] parameters, Object[] args) throws UnsupportedEncodingException { + Map queryVariableParamsMap = new HashMap<>(); + for (int i = 0; i < parameters.length; i++) { + Parameter parameter = parameters[i]; + if (!parameter.isAnnotationPresent(RequestParam.class)) { + continue; + } + RequestParam annotation = parameter.getAnnotation(RequestParam.class); + String variableName = annotation.value(); + if (StringUtils.isBlank(variableName)) { + throw new ParamsException("参数 " + parameter.getName() + " 名称不能为空"); + } + Object arg = args[i]; + if (arg == null) { + continue; + } + queryVariableParamsMap.put(variableName, URLEncoder.encode(arg.toString(), "UTF-8")); + } + return queryVariableParamsMap; + } + + /** + * 请求头 + * + * @param parameters + * @param args + * @return + */ + private Map getHeaderVariableParams(Parameter[] parameters, Object[] args) throws UnsupportedEncodingException { + Map headerVariableParamsMap = new HashMap<>(); + for (int i = 0; i < parameters.length; i++) { + Parameter parameter = parameters[i]; + if (!parameter.isAnnotationPresent(RequestHeader.class)) { + continue; + } + RequestHeader annotation = parameter.getAnnotation(RequestHeader.class); + String variableName = annotation.value(); + if (StringUtils.isBlank(variableName)) { + throw new ParamsException("参数 " + parameter.getName() + " 名称不能为空"); + } + Object arg = args[i]; + if (arg == null) { + continue; + } + headerVariableParamsMap.put(variableName, URLEncoder.encode(arg.toString(), "UTF-8")); + } + return headerVariableParamsMap; + } + + /** + * 获取请求体,只取第一个 + * + * @param parameters + * @param args + * @return + */ + private Object getRequestBody(Parameter[] parameters, Object[] args) { + for (int i = 0; i < parameters.length; i++) { + Parameter parameter = parameters[i]; + if (!parameter.isAnnotationPresent(RequestBody.class)) { + continue; + } + return args[i]; + } + return null; + } + + + /** + * 检查路径变量 + * + * @param pathVariables 路劲变量列表 + */ + private void checkPathVariables(List pathVariables) { + for (int i = 0; i < pathVariables.size() - 1; i++) { + for (int j = i + 1; j < pathVariables.size(); j++) { + if (StringUtils.equals(pathVariables.get(i), pathVariables.get(j))) { + throw new ParamsException("路径变量 " + pathVariables.get(i) + "[" + i + "] 与 " + pathVariables.get(j) + "[" + j + "] 重复"); + } + } + } + } + + /** + * 检查路径变量与参数 + * + * @param pathVariables 路劲变量列表 + * @param pathVariableParams 路径参数Map + */ + private void checkPathVariableParams(List pathVariables, Map pathVariableParams) { + if (pathVariables.size() != pathVariableParams.size()) { + throw new SystemException("路径变量与参数数量不一致"); + } + for (String pathVariable : pathVariables) { + boolean isExist = false; + for (Map.Entry kv : pathVariableParams.entrySet()) { + if (StringUtils.equals(pathVariable, kv.getKey())) { + isExist = true; + break; + } + } + if (!isExist) { + throw new ParamsException("路径变量" + pathVariable + " 不存在参数"); + } + } + } + + /** + * 校验请求主体 + * + * @param requestBody + */ + private void checkRequestBody(Object requestBody) { + if (requestBody == null) { + throw new ParamsException("请求主体不能为空"); + } + } + + /** + * 构建uri + * + * @param uri + * @param pathVariables + * @param pathVariableParams + * @return + */ + private String buildUri(String uri, List pathVariables, Map pathVariableParams) { + String resultUri = uri; + for (String pathVariable : pathVariables) { + resultUri = resultUri.replace("{" + pathVariable + "}", pathVariableParams.get(pathVariable)); + } + return resultUri; + } + + /** + * 构建完整路径 + * + * @param uri + * @param queryVariableParams + * @return + * @throws UnsupportedEncodingException + */ + private String buildFullUri(String uri, Map queryVariableParams) { + if (queryVariableParams.isEmpty()) { + return uri; + } + StringBuilder queryParams = new StringBuilder(); + for (Map.Entry kv : queryVariableParams.entrySet()) { + if (queryParams.length() > 0) { + queryParams.append("&"); + } + queryParams.append(kv.getKey()).append("=").append(kv.getValue()); + } + return uri + "?" + queryParams; } } diff --git a/basic-util/src/main/java/ink/wgink/util/remote/rest/proxy/RestRemoteProxy.java b/basic-util/src/main/java/ink/wgink/util/remote/rest/proxy/RestRemoteProxy.java index d351c061..ffe27960 100644 --- a/basic-util/src/main/java/ink/wgink/util/remote/rest/proxy/RestRemoteProxy.java +++ b/basic-util/src/main/java/ink/wgink/util/remote/rest/proxy/RestRemoteProxy.java @@ -1,6 +1,10 @@ package ink.wgink.util.remote.rest.proxy; import ink.wgink.util.remote.rest.handler.RestRemoteHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; import java.lang.reflect.Proxy; @@ -20,19 +24,13 @@ public class RestRemoteProxy { } public interface IDemo { - String say(); - } - - public static class DemoImpl implements IDemo { - @Override - public String say() { - return "go"; - } + @GetMapping("/demo/{p2}/{p1}") + String test(@PathVariable("p1") String p1, @PathVariable("p2") String p2, @RequestParam("q1") String q1, @RequestParam("q2") String q2, @RequestHeader("access_token") String token, @RequestHeader("auth") String auth); } public static void main(String[] args) { - IDemo demo = RestRemoteProxy.getInstance(IDemo.class); - System.out.println(demo.say()); + IDemo instance = RestRemoteProxy.getInstance(IDemo.class); + instance.test("pp1", "我是", null, "中国人", "token123456", null); } } diff --git a/basic-util/src/main/java/ink/wgink/util/remote/rest/request/RestRemoteRequest.java b/basic-util/src/main/java/ink/wgink/util/remote/rest/request/RestRemoteRequest.java new file mode 100644 index 00000000..baafa51a --- /dev/null +++ b/basic-util/src/main/java/ink/wgink/util/remote/rest/request/RestRemoteRequest.java @@ -0,0 +1,14 @@ +package ink.wgink.util.remote.rest.request; + +/** + * When you feel like quitting. Think about why you started + * 当你想要放弃的时候,想想当初你为何开始 + * + * @ClassName: RestRemoteRequest + * @Description: Rest远程调用请求 + * @Author: WangGeng + * @Date: 2021/9/18 21:00 + * @Version: 1.0 + **/ +public class RestRemoteRequest { +}