http接口封装基础调通

This commit is contained in:
aoshiguchen
2022-07-17 13:11:50 +08:00
parent 40e93a29bd
commit 317a390b79
7 changed files with 269 additions and 6 deletions
@@ -25,6 +25,8 @@ package fun.asgc.neutrino.core.util;
import fun.asgc.neutrino.core.annotation.Component; import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.bean.BeanFactory; import fun.asgc.neutrino.core.bean.BeanFactory;
import fun.asgc.neutrino.core.bean.BeanFactoryAware; import fun.asgc.neutrino.core.bean.BeanFactoryAware;
import fun.asgc.neutrino.core.bean.BeanIdentity;
import fun.asgc.neutrino.core.exception.BeanException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.List; import java.util.List;
@@ -58,6 +60,20 @@ public class BeanManager implements BeanFactoryAware {
return beanFactory.getBean(clazz); return beanFactory.getBean(clazz);
} }
/**
* 尝试根据Bean身份标识获取bean
* @param identity
* @param <T>
* @return
* @throws BeanException
*/
public static <T> T getBean(BeanIdentity identity) {
if (null == beanFactory) {
throw new RuntimeException("BeanFactory尚未初始化");
}
return beanFactory.getBean(identity);
}
/** /**
* 根据超类获取bean集合 * 根据超类获取bean集合
* @param superClass * @param superClass
@@ -21,19 +21,30 @@
*/ */
package fun.asgc.neutrino.core.web; package fun.asgc.neutrino.core.web;
import com.alibaba.fastjson.JSONObject;
import fun.asgc.neutrino.core.annotation.Autowired; import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component; import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept; import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.context.ApplicationConfig; import fun.asgc.neutrino.core.context.ApplicationConfig;
import fun.asgc.neutrino.core.util.*;
import fun.asgc.neutrino.core.web.router.DefaultHttpRouter; import fun.asgc.neutrino.core.web.router.DefaultHttpRouter;
import fun.asgc.neutrino.core.web.router.HttpRouteParam;
import fun.asgc.neutrino.core.web.router.HttpRouteResult;
import fun.asgc.neutrino.core.web.router.HttpRouterType;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.*;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationTargetException;
/** /**
* *
* @author: aoshiguchen * @author: aoshiguchen
* @date: 2022/7/15 * @date: 2022/7/15
*/ */
@Slf4j
@NonIntercept @NonIntercept
@Component @Component
public class HttpRequestHandler { public class HttpRequestHandler {
@@ -41,10 +52,66 @@ public class HttpRequestHandler {
private ApplicationConfig applicationConfig; private ApplicationConfig applicationConfig;
@Autowired @Autowired
private DefaultHttpRouter defaultHttpRouter; private DefaultHttpRouter defaultHttpRouter;
private static volatile String httpContextPath;
public void handle(ChannelHandlerContext context, FullHttpRequest request) { public void handle(ChannelHandlerContext context, FullHttpRequest request) {
// TODO String routePath = getRoutePath(request.uri());
System.out.println("hello"); HttpMethod httpMethod = HttpMethod.of(request.method().name());
HttpRouteResult httpRouteResult = defaultHttpRouter.route(new HttpRouteParam().setMethod(httpMethod).setUrl(routePath));
if (null == httpRouteResult) {
HttpServerUtil.send404Response(context, request.uri());
return;
}
if (HttpRouterType.METHOD == httpRouteResult.getType()) {
try {
Object invokeResult = httpRouteResult.getMethod().invoke(httpRouteResult.getInstance());
String res = String.valueOf(invokeResult);
if (!TypeUtil.isNormalBasicType(invokeResult.getClass())) {
res = JSONObject.toJSONString(invokeResult);
}
FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(res.getBytes()));
fullHttpResponse.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON);
context.writeAndFlush(fullHttpResponse).addListener(ChannelFutureListener.CLOSE);
return;
} catch (Exception e) {
// TODO
}
} else {
// TODO
HttpServerUtil.send404Response(context, request.uri());
return;
}
} }
private String getRoutePath(String url) {
String httpContextPath = getHttpContextPath();
if (StringUtil.isEmpty(httpContextPath)) {
return url;
}
String res = url.substring(httpContextPath.length());
if (StringUtil.isEmpty(res)) {
return "/";
}
return res;
}
private String getHttpContextPath() {
return LockUtil.doubleCheckProcessForNoException(
() -> null == httpContextPath,
this,
() -> {
httpContextPath = applicationConfig.getHttp().getContextPath();
if (StringUtil.isEmpty(httpContextPath)) {
httpContextPath = "/";
}
if (!httpContextPath.startsWith("/")) {
httpContextPath = "/" + httpContextPath;
}
if (httpContextPath.endsWith("/")) {
httpContextPath = httpContextPath.substring(0, httpContextPath.length() - 1);
}
},
() -> httpContextPath
);
}
} }
@@ -21,14 +21,27 @@
*/ */
package fun.asgc.neutrino.core.web.router; package fun.asgc.neutrino.core.web.router;
import com.google.common.collect.Sets;
import fun.asgc.neutrino.core.annotation.*; import fun.asgc.neutrino.core.annotation.*;
import fun.asgc.neutrino.core.bean.BeanWrapper; import fun.asgc.neutrino.core.bean.BeanWrapper;
import fun.asgc.neutrino.core.bean.SimpleBeanFactory; import fun.asgc.neutrino.core.bean.SimpleBeanFactory;
import fun.asgc.neutrino.core.util.ArrayUtil;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.ReflectUtil;
import fun.asgc.neutrino.core.web.HttpMethod;
import fun.asgc.neutrino.core.web.annotation.GetMapping;
import fun.asgc.neutrino.core.web.annotation.PostMapping;
import fun.asgc.neutrino.core.web.annotation.RequestMapping;
import fun.asgc.neutrino.core.web.annotation.RestController;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* 默认的http路由器 * 默认的http路由器
@@ -50,7 +63,125 @@ public class DefaultHttpRouter implements HttpRouter {
public void init() { public void init() {
log.debug("Http路由器初始化..."); log.debug("Http路由器初始化...");
List<BeanWrapper> beanWrapperList = webApplicationBeanFactory.beanWrapperList(); List<BeanWrapper> beanWrapperList = webApplicationBeanFactory.beanWrapperList();
// TODO 路由初始化 beanWrapperList.forEach(beanWrapper -> {
RestController restController = beanWrapper.getType().getAnnotation(RestController.class);
if (null == restController) {
return;
}
Set<HttpMethod> methods = null;
Set<String> paths = null;
if (beanWrapper.getType().isAnnotationPresent(GetMapping.class)) {
GetMapping getMapping = beanWrapper.getType().getAnnotation(GetMapping.class);
methods = Sets.newHashSet(HttpMethod.GET);
if (ArrayUtil.notEmpty(getMapping.value())) {
paths = Stream.of(getMapping.value()).collect(Collectors.toSet());
}
} else if (beanWrapper.getType().isAnnotationPresent(PostMapping.class)) {
PostMapping postMapping = beanWrapper.getType().getAnnotation(PostMapping.class);
methods = Sets.newHashSet(HttpMethod.POST);
if (ArrayUtil.notEmpty(postMapping.value())) {
paths = Stream.of(postMapping.value()).collect(Collectors.toSet());
}
} else if (beanWrapper.getType().isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestMapping = beanWrapper.getType().getAnnotation(RequestMapping.class);
if (ArrayUtil.notEmpty(requestMapping.value())) {
paths = Stream.of(requestMapping.value()).collect(Collectors.toSet());
}
if (ArrayUtil.notEmpty(requestMapping.method())) {
methods = Stream.of(requestMapping.method()).collect(Collectors.toSet());
}
}
if (CollectionUtil.isEmpty(methods)){
methods = Stream.of(HttpMethod.values()).collect(Collectors.toSet());
}
if (CollectionUtil.isEmpty(paths)) {
paths = Sets.newHashSet("");
}
paths = paths.stream().map(p -> {
if (p.endsWith("/")) {
return p.substring(0, p.length() - 1);
}
return p;
}).collect(Collectors.toSet());
methodScan(beanWrapper, methods, paths);
});
}
private void methodScan(BeanWrapper beanWrapper, Set<HttpMethod> httpMethods, Set<String> paths) {
Set<Method> methods = ReflectUtil.getDeclaredMethods(beanWrapper.getType());
methods.forEach(method -> {
Set<HttpMethod> realityHttpMethods = null;
Set<String> subPaths = null;
if (method.isAnnotationPresent(GetMapping.class)) {
GetMapping getMapping = method.getAnnotation(GetMapping.class);
if (!httpMethods.contains(HttpMethod.GET)) {
throw new RuntimeException(String.format("Controller[type:%s, name:%s] method:%s 方法上的GetMapping注解与类的声明发生冲突!", beanWrapper.getType().getName(), beanWrapper.getName(), method.toString()));
}
realityHttpMethods = Sets.newHashSet(HttpMethod.GET);
if (ArrayUtil.notEmpty(getMapping.value())) {
subPaths = Stream.of(getMapping.value()).collect(Collectors.toSet());
}
} else if (method.isAnnotationPresent(PostMapping.class)) {
PostMapping postMapping = method.getAnnotation(PostMapping.class);
if (!httpMethods.contains(HttpMethod.POST)) {
throw new RuntimeException(String.format("Controller[type:%s, name:%s] method:%s 方法上的PostMapping注解与类的声明发生冲突!", beanWrapper.getType().getName(), beanWrapper.getName(), method.toString()));
}
realityHttpMethods = Sets.newHashSet(HttpMethod.POST);
if (ArrayUtil.notEmpty(postMapping.value())) {
subPaths = Stream.of(postMapping.value()).collect(Collectors.toSet());
}
} else if (method.isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
if (ArrayUtil.notEmpty(requestMapping.method())) {
realityHttpMethods = Stream.of(requestMapping.method()).collect(Collectors.toSet());
}
if (!httpMethods.containsAll(realityHttpMethods)) {
throw new RuntimeException(String.format("Controller[type:%s, name:%s] method:%s 方法上的RequestMapping注解与类的声明发生冲突!", beanWrapper.getType().getName(), beanWrapper.getName(), method.toString()));
}
if (ArrayUtil.notEmpty(requestMapping.value())) {
subPaths = Stream.of(requestMapping.value()).collect(Collectors.toSet());
}
} else {
return;
}
if (CollectionUtil.isEmpty(realityHttpMethods)) {
realityHttpMethods = Sets.newHashSet(httpMethods);
}
if (CollectionUtil.isEmpty(subPaths)) {
subPaths = Sets.newHashSet("/");
}
subPaths = subPaths.stream().map(p -> {
if (!p.startsWith("/")) {
return "/" + p;
}
return p;
}).collect(Collectors.toSet());
addRoute(beanWrapper, method, realityHttpMethods, paths, subPaths);
});
}
private void addRoute(BeanWrapper beanWrapper, Method method, Set<HttpMethod> httpMethods, Set<String> paths, Set<String> subPaths) {
for (HttpMethod httpMethod : httpMethods) {
for (String path : paths) {
for (String subPath : subPaths) {
addRoute(beanWrapper, method, httpMethod, path + subPath);
}
}
}
}
private synchronized void addRoute(BeanWrapper beanWrapper, Method method, HttpMethod httpMethod, String path) {
log.info("addRoute[{}#{}] httpMethod:{} path:{}", beanWrapper.getType().getName(), method.getName(), httpMethod.name(), path);
HttpRouteIdentity identity = new HttpRouteIdentity(httpMethod, path);
if (routeCache.containsKey(identity)) {
throw new RuntimeException(String.format("Controller[type:%s, name:%s] method:%s 路由存在重复!", beanWrapper.getType().getName(), beanWrapper.getName(), method.getName()));
}
routeCache.put(identity, new HttpRouteInfo()
.setType(HttpRouterType.METHOD)
.setMethod(method)
.setBeanIdentity(beanWrapper.getIdentity())
);
} }
@Override @Override
@@ -75,5 +206,4 @@ public class DefaultHttpRouter implements HttpRouter {
public void destroy() { public void destroy() {
log.debug("Http路由器销毁..."); log.debug("Http路由器销毁...");
} }
} }
@@ -55,7 +55,7 @@ public class HttpRouteIdentity implements Identity {
Assert.notEmpty(url, "url不能为空!"); Assert.notEmpty(url, "url不能为空!");
this.method = method; this.method = method;
this.url = url; this.url = url;
this.identityHashCode = System.identityHashCode(url); this.identityHashCode = System.identityHashCode(method);
} }
public HttpMethod getMethod() { public HttpMethod getMethod() {
@@ -23,6 +23,7 @@ package fun.asgc.neutrino.core.web.router;
import fun.asgc.neutrino.core.bean.BeanIdentity; import fun.asgc.neutrino.core.bean.BeanIdentity;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -31,6 +32,7 @@ import java.lang.reflect.Method;
* @author: aoshiguchen * @author: aoshiguchen
* @date: 2022/7/16 * @date: 2022/7/16
*/ */
@Accessors(chain = true)
@Data @Data
public class HttpRouteInfo { public class HttpRouteInfo {
/** /**
@@ -23,12 +23,14 @@ package fun.asgc.neutrino.core.web.router;
import fun.asgc.neutrino.core.web.HttpMethod; import fun.asgc.neutrino.core.web.HttpMethod;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors;
/** /**
* http路由参数 * http路由参数
* @author: aoshiguchen * @author: aoshiguchen
* @date: 2022/7/16 * @date: 2022/7/16
*/ */
@Accessors(chain = true)
@Data @Data
public class HttpRouteParam { public class HttpRouteParam {
private HttpMethod method; private HttpMethod method;
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.controller;
import fun.asgc.neutrino.core.web.annotation.GetMapping;
import fun.asgc.neutrino.core.web.annotation.RequestMapping;
import fun.asgc.neutrino.core.web.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* @author: aoshiguchen
* @date: 2022/7/17
*/
@RestController
@RequestMapping("/test1")
public class Test1Controller {
private static final SimpleDateFormat SDF = new SimpleDateFormat( "yyyy-MM-dd :HH:mm:ss");
@GetMapping("hello")
public String hello() {
return "hello 现在时间是:" + SDF.format(new Date());
}
}