diff --git a/README.md b/README.md index af317602f..5afd9e48f 100644 --- a/README.md +++ b/README.md @@ -64,14 +64,14 @@ Run with `Maven`: com.bladejava blade-mvc - 2.0.12.BETA + 2.0.12.RELEASE ``` or `Gradle`: ```sh -compile 'com.bladejava:blade-mvc:2.0.12.BETA' +compile 'com.bladejava:blade-mvc:2.0.12.RELEASE' ``` Write the `main` method and the `Hello World`: diff --git a/README_CN.md b/README_CN.md index a4a3997bc..1389fa758 100644 --- a/README_CN.md +++ b/README_CN.md @@ -61,7 +61,7 @@ com.bladejava blade-mvc - 2.0.12.BETA + 2.0.12.RELEASE ``` @@ -70,7 +70,7 @@ 或者 `Gradle`: ```sh -compile 'com.bladejava:blade-mvc:2.0.12.BETA' +compile 'com.bladejava:blade-mvc:2.0.12.RELEASE' ``` 编写 `main` 函数写一个 `Hello World`: diff --git a/pom.xml b/pom.xml index d528325f9..e211fd3fd 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bladejava blade-mvc - 2.0.12.BETA + 2.0.12.RELEASE jar blade diff --git a/src/main/java/com/blade/Blade.java b/src/main/java/com/blade/Blade.java index a26afd402..3bba34ca0 100644 --- a/src/main/java/com/blade/Blade.java +++ b/src/main/java/com/blade/Blade.java @@ -153,6 +153,8 @@ public class Blade { */ private ExceptionHandler exceptionHandler = new DefaultExceptionHandler(); + private CorsMiddleware corsMiddleware; + /** * Used to identify whether the web server has started */ @@ -548,11 +550,15 @@ public Blade enableCors(boolean enableCors) { public Blade enableCors(boolean enableCors, CorsConfiger corsConfig) { this.environment.set(ENV_KEY_CORS_ENABLE, enableCors); if (enableCors) { - this.use(new CorsMiddleware(corsConfig)); + this.corsMiddleware = new CorsMiddleware(corsConfig); } return this; } + public CorsMiddleware corsMiddleware() { + return corsMiddleware; + } + /** * Get blade statics list. * e.g: "/favicon.ico", "/robots.txt", "/static/", "/upload/", "/webjars/" @@ -1103,4 +1109,5 @@ private void loadConfig(String[] args) { } } + } \ No newline at end of file diff --git a/src/main/java/com/blade/ioc/annotation/Bean.java b/src/main/java/com/blade/ioc/annotation/Bean.java index 267d4a8cc..6342e5602 100644 --- a/src/main/java/com/blade/ioc/annotation/Bean.java +++ b/src/main/java/com/blade/ioc/annotation/Bean.java @@ -15,6 +15,7 @@ String value() default ""; + @Deprecated boolean singleton() default true; } \ No newline at end of file diff --git a/src/main/java/com/blade/ioc/annotation/Inject.java b/src/main/java/com/blade/ioc/annotation/Inject.java index a23c2ae90..ac9b5f8cd 100644 --- a/src/main/java/com/blade/ioc/annotation/Inject.java +++ b/src/main/java/com/blade/ioc/annotation/Inject.java @@ -17,6 +17,4 @@ String value() default ""; - boolean singleton() default true; - } \ No newline at end of file diff --git a/src/main/java/com/blade/kit/IocKit.java b/src/main/java/com/blade/kit/IocKit.java index c3f546a27..b90bd46b9 100644 --- a/src/main/java/com/blade/kit/IocKit.java +++ b/src/main/java/com/blade/kit/IocKit.java @@ -17,7 +17,6 @@ import com.blade.Environment; import com.blade.ioc.Ioc; -import com.blade.ioc.annotation.Bean; import com.blade.ioc.annotation.Inject; import com.blade.ioc.annotation.InjectWith; import com.blade.ioc.annotation.Value; @@ -25,8 +24,6 @@ import com.blade.ioc.bean.ClassDefine; import com.blade.ioc.bean.FieldInjector; import com.blade.ioc.bean.ValueInjector; -import com.blade.mvc.WebContext; -import com.blade.mvc.annotation.Path; import lombok.experimental.UtilityClass; import java.lang.reflect.Field; @@ -132,18 +129,6 @@ public static void injectionValue(Environment environment, BeanDefine beanDefine } public static boolean isSingleton(Class type) { - Bean bean = type.getAnnotation(Bean.class); - if (null != bean) { - return bean.singleton(); - } - Path path = type.getAnnotation(Path.class); - if (null != path) { - return path.singleton(); - } - Inject inject = type.getAnnotation(Inject.class); - if (null != inject) { - return inject.singleton(); - } return true; } diff --git a/src/main/java/com/blade/mvc/Const.java b/src/main/java/com/blade/mvc/Const.java index 27bb935f9..949992f11 100644 --- a/src/main/java/com/blade/mvc/Const.java +++ b/src/main/java/com/blade/mvc/Const.java @@ -31,7 +31,7 @@ public interface Const { int DEFAULT_SERVER_PORT = 9000; String DEFAULT_SERVER_ADDRESS = "0.0.0.0"; String LOCAL_IP_ADDRESS = "127.0.0.1"; - String VERSION = "2.0.12.BETA"; + String VERSION = "2.0.12.RELEASE"; String WEB_JARS = "/webjars/"; String CLASSPATH = BladeKit.getCurrentClassPath(); String CONTENT_TYPE_HTML = "text/html; charset=UTF-8"; diff --git a/src/main/java/com/blade/mvc/RouteContext.java b/src/main/java/com/blade/mvc/RouteContext.java index 857bea275..b7e24937a 100644 --- a/src/main/java/com/blade/mvc/RouteContext.java +++ b/src/main/java/com/blade/mvc/RouteContext.java @@ -17,6 +17,7 @@ import com.blade.ioc.bean.BeanDefine; import com.blade.kit.IocKit; +import com.blade.mvc.handler.RouteHandler; import com.blade.mvc.http.Body; import com.blade.mvc.http.Request; import com.blade.mvc.http.Response; @@ -46,6 +47,7 @@ public class RouteContext { private Request request; private Response response; private Object[] routeActionParameters; + private boolean abort; private static final String LAMBDA_IDENTIFY = "$$Lambda$"; @@ -521,25 +523,35 @@ public Object[] routeParameters() { return this.routeActionParameters; } + public void abort() { + this.abort = true; + } + + public boolean isAbort() { + return this.abort; + } + public void initRoute(Route route) { this.request.initPathParams(route); this.route = route; - - boolean singleton = IocKit.isSingleton(route.getTargetType()); - - if (singleton) { - BeanDefine beanDefine = WebContext.blade().ioc().getBeanDefine(route.getTargetType()); - if(beanDefine.isFieldHasPrototype()){ - // reset initialize - IocKit.injection(WebContext.blade().ioc(), beanDefine); - } else { - Object target = WebContext.blade().ioc().getBean(route.getTargetType()); - this.route.setTarget(target); - } - } else { - Object target = WebContext.blade().ioc().createBean(route.getTargetType()); - this.route.setTarget(target); - } +// if (null != route.getTarget() && route.getTargetType().equals(RouteHandler.class)) { +// return; +// } +// boolean singleton = IocKit.isSingleton(route.getTargetType()); +// +// if (singleton) { +// BeanDefine beanDefine = WebContext.blade().ioc().getBeanDefine(route.getTargetType()); +// if (beanDefine.isFieldHasPrototype()) { +// // reset initialize +// IocKit.injection(WebContext.blade().ioc(), beanDefine); +// } else { +// Object target = WebContext.blade().ioc().getBean(route.getTargetType()); +// this.route.setTarget(target); +// } +// } else { +// Object target = WebContext.blade().ioc().createBean(route.getTargetType()); +// this.route.setTarget(target); +// } } public void injectParameters() { diff --git a/src/main/java/com/blade/mvc/annotation/Path.java b/src/main/java/com/blade/mvc/annotation/Path.java index c0cf6559b..d0f7572ac 100644 --- a/src/main/java/com/blade/mvc/annotation/Path.java +++ b/src/main/java/com/blade/mvc/annotation/Path.java @@ -31,12 +31,6 @@ */ boolean restful() default false; - /** - * @return Whether to create a controller as a singleton, the default is. - * When false, a new controller instance is created for each request. - */ - boolean singleton() default true; - /** * @return path description */ diff --git a/src/main/java/com/blade/security/web/cors/CorsMiddleware.java b/src/main/java/com/blade/security/web/cors/CorsMiddleware.java index aea32749b..fd9078e47 100644 --- a/src/main/java/com/blade/security/web/cors/CorsMiddleware.java +++ b/src/main/java/com/blade/security/web/cors/CorsMiddleware.java @@ -1,19 +1,24 @@ package com.blade.security.web.cors; import com.blade.mvc.RouteContext; -import com.blade.mvc.hook.WebHook; +import com.blade.mvc.handler.RouteHandler; +import com.blade.mvc.http.Response; +import lombok.extern.slf4j.Slf4j; + import java.util.StringJoiner; import java.util.stream.Collector; -import lombok.extern.slf4j.Slf4j; /** * CorsMiddleware + *

+ * This is a simple CORS policy, + * you can also implement the {@link CorsMiddleware#handle} method of the class to perform custom filtering. * * @author biezhi * @date 2018/7/11 */ @Slf4j -public class CorsMiddleware implements WebHook { +public class CorsMiddleware implements RouteHandler { private CorsConfiger corsConfig; @@ -25,79 +30,76 @@ public CorsMiddleware(CorsConfiger corsConfiger) { } @Override - public boolean before(RouteContext context) { - this.allowCredentials(context) - .allowMethods(context) - .allowHeads(context) - .setMaxAge(context) - .allowCredentials(context); - if ("OPTIONS".equals(context.method())) { - context.status(202); - } - return true; + public void handle(RouteContext context) { + context.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE"); + context.header("Access-Control-Allow-Origin", "*"); + context.header("Access-Control-Allow-Headers", CorsConfiger.ALL); + context.status(204); } - private CorsMiddleware allowHeads(RouteContext context) { + private CorsMiddleware allowHeads(Response response) { boolean isDefaultAllowHeads = corsConfig == null || corsConfig.getAllowedHeaders() == null - || corsConfig.getAllowedHeaders().size() == 0; + || corsConfig.getAllowedHeaders().size() == 0; if (isDefaultAllowHeads) { - context.response().header("Access-Control-Allow-Headers", CorsConfiger.ALL); + response.header("Access-Control-Allow-Headers", CorsConfiger.ALL); return this; } - String heads = corsConfig.getAllowedHeaders().stream().collect(Collector.of( - () -> new StringJoiner(","), - (j, head) -> j.add(head), - StringJoiner::merge, - StringJoiner::toString - )); - context.response().header("Access-Control-Allow-Headers", heads); + String heads = corsConfig.getAllowedHeaders().stream() + .collect(Collector.of( + () -> new StringJoiner(","), + StringJoiner::add, + StringJoiner::merge, + StringJoiner::toString + )); + + response.header("Access-Control-Allow-Headers", heads); return this; } - private CorsMiddleware allowMethods(RouteContext context) { + private CorsMiddleware allowMethods(Response response) { boolean isDefaultAllowMethods = corsConfig == null || corsConfig.getAllowedMethods() == null - || corsConfig.getAllowedMethods().size() == 0; + || corsConfig.getAllowedMethods().size() == 0; if (isDefaultAllowMethods) { - context.header("Access-Control-Allow-Methods", - CorsConfiger.DEFAULT_ALLOWED_METHODS); + response.header("Access-Control-Allow-Methods", + CorsConfiger.DEFAULT_ALLOWED_METHODS); return this; } String methods = corsConfig.getAllowedMethods().stream().collect(Collector.of( - () -> new StringJoiner(", "), - (j, method) -> j.add(method.toUpperCase()), - StringJoiner::merge, - StringJoiner::toString + () -> new StringJoiner(", "), + (j, method) -> j.add(method.toUpperCase()), + StringJoiner::merge, + StringJoiner::toString )); - context.response().header("Access-Control-Allow-Methods", methods); + response.header("Access-Control-Allow-Methods", methods); return this; } - private CorsMiddleware allowCredentials(RouteContext context) { + private CorsMiddleware allowCredentials(Response response) { boolean isDefaultAllowCredentials = corsConfig == null || corsConfig.getAllowCredentials() == null; if (isDefaultAllowCredentials) { - context.header("Access-Control-Allow-Credentials", - CorsConfiger.DEFAULT_ALLOW_CREDENTIALS); + response.header("Access-Control-Allow-Credentials", + CorsConfiger.DEFAULT_ALLOW_CREDENTIALS); return this; } - context.response().header("Access-Control-Allow-Credentials", - corsConfig.getAllowCredentials().toString()); + response.header("Access-Control-Allow-Credentials", + corsConfig.getAllowCredentials().toString()); return this; } - private CorsMiddleware setMaxAge(RouteContext context) { + private CorsMiddleware setMaxAge(Response response) { boolean isDefaultMaxAge = corsConfig == null || corsConfig.getMaxAge() == null; if (isDefaultMaxAge) { - context.response().header("Access-Control-Max-Age", - CorsConfiger.DEFAULT_MAX_AGE.toString()); + response.header("Access-Control-Max-Age", + CorsConfiger.DEFAULT_MAX_AGE.toString()); return this; } - context.header("Access-Control-Max-Age", corsConfig.getMaxAge().toString()); + response.header("Access-Control-Max-Age", corsConfig.getMaxAge().toString()); return this; } diff --git a/src/main/java/com/blade/server/netty/HttpServerHandler.java b/src/main/java/com/blade/server/netty/HttpServerHandler.java index 543100d9b..dc63246a8 100644 --- a/src/main/java/com/blade/server/netty/HttpServerHandler.java +++ b/src/main/java/com/blade/server/netty/HttpServerHandler.java @@ -18,12 +18,10 @@ import com.blade.exception.BladeException; import com.blade.exception.NotFoundException; import com.blade.kit.BladeCache; +import com.blade.mvc.RouteContext; import com.blade.mvc.WebContext; import com.blade.mvc.handler.ExceptionHandler; -import com.blade.mvc.http.HttpRequest; -import com.blade.mvc.http.HttpResponse; -import com.blade.mvc.http.Request; -import com.blade.mvc.http.Response; +import com.blade.mvc.http.*; import com.blade.mvc.route.Route; import com.blade.mvc.route.RouteMatcher; import io.netty.channel.ChannelFutureListener; @@ -67,10 +65,10 @@ public class HttpServerHandler extends SimpleChannelInboundHandler WebContext.blade().environment() .getBoolean(ENV_KEY_PERFORMANCE, false); - private final StaticFileHandler staticFileHandler = new StaticFileHandler(WebContext.blade()); - private final RouteMethodHandler routeHandler = new RouteMethodHandler(); - private final Set notStaticUri = new HashSet<>(32); - private final RouteMatcher routeMatcher = WebContext.blade().routeMatcher(); + private final StaticFileHandler staticFileHandler = new StaticFileHandler(WebContext.blade()); + private final RouteMethodHandler routeHandler = new RouteMethodHandler(); + private final Set notStaticUri = new HashSet<>(32); + private final RouteMatcher routeMatcher = WebContext.blade().routeMatcher(); @Override public void channelReadComplete(ChannelHandlerContext ctx) { @@ -104,10 +102,10 @@ private void writeResponse(ChannelHandlerContext ctx, CompletableFuture { private final HttpServerHandler httpServerHandler; private final SslContext sslCtx; - private final Blade blade; - private final boolean enableCors; - private final boolean isWebSocket; - private final boolean useGZIP; + private final Blade blade; + private final boolean isWebSocket; + private final boolean useGZIP; public static volatile String date = DateKit.gmtDate(LocalDateTime.now()); @@ -41,7 +40,6 @@ public class HttpServerInitializer extends ChannelInitializer { public HttpServerInitializer(SslContext sslCtx, Blade blade, ScheduledExecutorService service) { this.sslCtx = sslCtx; this.blade = blade; - this.enableCors = blade.environment().getBoolean(Const.ENV_KEY_CORS_ENABLE, false); this.useGZIP = blade.environment().getBoolean(Const.ENV_KEY_GZIP_ENABLE, false); this.isWebSocket = StringKit.isNotEmpty(blade.webSocketPath()); @@ -69,10 +67,6 @@ protected void initChannel(SocketChannel ch) { pipeline.addLast(new HttpContentCompressor()); } - if (enableCors) { - pipeline.addLast(new CorsHandler(CorsConfigBuilder.forAnyOrigin().allowNullOrigin().allowCredentials().build())); - } - if (isWebSocket) { pipeline.addLast(new WebSocketServerProtocolHandler(blade.webSocketPath(), null, true)); pipeline.addLast(WEB_SOCKET_HANDLER); diff --git a/src/main/java/com/blade/server/netty/NettyServer.java b/src/main/java/com/blade/server/netty/NettyServer.java index 02cd77110..29fb01d4c 100644 --- a/src/main/java/com/blade/server/netty/NettyServer.java +++ b/src/main/java/com/blade/server/netty/NettyServer.java @@ -291,8 +291,7 @@ private void parseAndCreate(Class clazz) { blade.register(clazz); } if (null != clazz.getAnnotation(Path.class)) { - Path path = clazz.getAnnotation(Path.class); - if (path.singleton() && null == blade.ioc().getBean(clazz)) { + if (null == blade.ioc().getBean(clazz)) { blade.register(clazz); } Object controller = blade.ioc().getBean(clazz); diff --git a/src/main/java/com/blade/server/netty/RouteMethodHandler.java b/src/main/java/com/blade/server/netty/RouteMethodHandler.java index 6ae914871..30338c3e1 100644 --- a/src/main/java/com/blade/server/netty/RouteMethodHandler.java +++ b/src/main/java/com/blade/server/netty/RouteMethodHandler.java @@ -224,7 +224,6 @@ private void routeHandle(RouteContext context) { if (null == target) { Class clazz = context.routeAction().getDeclaringClass(); target = WebContext.blade().getBean(clazz); -// context.route().setTarget(target); } if (context.targetType() == RouteHandler.class) { RouteHandler routeHandler = (RouteHandler) target; @@ -239,10 +238,7 @@ private void routeHandle(RouteContext context) { Path path = target.getClass().getAnnotation(Path.class); JSON JSON = actionMethod.getAnnotation(JSON.class); - boolean isRestful = (null != JSON) || (null != path && path.restful()); - boolean isSingleton = path.singleton(); - - target = isSingleton ? target : WebContext.blade().ioc().createBean(target.getClass()); + boolean isRestful = (null != JSON) || (null != path && path.restful()); // if request is restful and not InternetExplorer userAgent if (isRestful) { @@ -330,9 +326,7 @@ private boolean invokeHook(RouteContext context, Route hookRoute) throws Excepti return true; } - private boolean invokeMiddleware(List middleware, - RouteContext context) throws BladeException { - + private boolean invokeMiddleware(List middleware, RouteContext context) throws BladeException { if (BladeKit.isEmpty(middleware)) { return true; } @@ -356,6 +350,9 @@ private boolean invokeHook(List hooks, RouteContext context) throws Excep if (hook.getTargetType() == RouteHandler.class) { RouteHandler routeHandler = (RouteHandler) hook.getTarget(); routeHandler.handle(context); + if (context.isAbort()) { + return false; + } } else if (hook.getTargetType() == RouteHandler0.class) { RouteHandler0 routeHandler = (RouteHandler0) hook.getTarget(); routeHandler.handle(context.request(), context.response()); diff --git a/src/main/java/com/blade/server/netty/StaticFileHandler.java b/src/main/java/com/blade/server/netty/StaticFileHandler.java index 4874c4755..2c345f946 100644 --- a/src/main/java/com/blade/server/netty/StaticFileHandler.java +++ b/src/main/java/com/blade/server/netty/StaticFileHandler.java @@ -135,7 +135,7 @@ public void handle(WebContext webContext) throws Exception { // gradle resources path File resourcesDirectory = new File(new File(Const.class.getResource("/").getPath()).getParent() + "/resources"); if (resourcesDirectory.isDirectory()) { - file = new File(resourcesDirectory.getPath() + "/resources/" + cleanUri.substring(1)); + file = new File(resourcesDirectory.getPath() + "/" + cleanUri.substring(1)); if (file.isHidden() || !file.exists()) { log404(log, method, uri); throw new NotFoundException(uri); diff --git a/src/test/java/netty_hello/BService.java b/src/test/java/netty_hello/BService.java index 106d7e676..b0488fc4e 100644 --- a/src/test/java/netty_hello/BService.java +++ b/src/test/java/netty_hello/BService.java @@ -6,7 +6,7 @@ * @author biezhi * @date 2018-11-21 */ -@Bean(singleton = false) +@Bean public class BService { public void sayHello(){ diff --git a/src/test/java/netty_hello/Hello.java b/src/test/java/netty_hello/Hello.java index fc4b2b7c9..0ac2ca83a 100644 --- a/src/test/java/netty_hello/Hello.java +++ b/src/test/java/netty_hello/Hello.java @@ -16,6 +16,7 @@ * 2017/6/5 */ public class Hello { + private static final StringBody hello = StringBody.of("Hello World."); public static void main(String[] args) { @@ -24,6 +25,7 @@ public static void main(String[] args) { String[] chars = new String[]{"Here a special char \" that not escaped", "And Another \\ char"}; ctx.json(chars); }) + .get("/user/aa", ctx -> ctx.render("upload.html")) .get("/up", ctx -> ctx.render("upload.html")) .get("/d1", ctx -> { File file = new File("/Users/biezhi/Pictures/rand/003.jpg"); @@ -78,6 +80,14 @@ public static void main(String[] args) { } }) + .before("/user/*", ctx -> + { + System.out.println("before: " + ctx.uri()); + ctx.text("Hello World"); + ctx.abort(); + } + ) + .enableCors(true) .event(EventType.ENVIRONMENT_CHANGED, new ConfigChanged()) .event(EventType.SESSION_DESTROY, e -> { System.out.println("session 失效了"); diff --git a/src/test/java/netty_hello/UserService.java b/src/test/java/netty_hello/UserService.java index 7e16ab0d6..15d66fca3 100644 --- a/src/test/java/netty_hello/UserService.java +++ b/src/test/java/netty_hello/UserService.java @@ -7,7 +7,7 @@ * @author biezhi * @date 2018-11-21 */ -@Bean(singleton = false) +@Bean public class UserService { @Inject