From 80bc66f856092ca81ef9fa945c3c5f16bc1b1bac Mon Sep 17 00:00:00 2001 From: psh686868 Date: Fri, 2 Nov 2018 14:57:07 +0800 Subject: [PATCH 01/21] =?UTF-8?q?=F0=9F=90=99update:=20Cors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/blade/Blade.java | 14 +++- .../blade/security/web/cors/CorsConfiger.java | 39 ++++++++++ .../security/web/cors/CorsMiddleware.java | 76 ++++++++++++++++++- 3 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/blade/security/web/cors/CorsConfiger.java diff --git a/src/main/java/com/blade/Blade.java b/src/main/java/com/blade/Blade.java index ed9f1a229..5fd08add6 100644 --- a/src/main/java/com/blade/Blade.java +++ b/src/main/java/com/blade/Blade.java @@ -35,6 +35,7 @@ import com.blade.mvc.route.RouteMatcher; import com.blade.mvc.ui.template.DefaultEngine; import com.blade.mvc.ui.template.TemplateEngine; +import com.blade.security.web.cors.CorsConfiger; import com.blade.security.web.cors.CorsMiddleware; import com.blade.server.Server; import com.blade.server.netty.NettyServer; @@ -534,9 +535,20 @@ public Class bootClass() { * @return blade */ public Blade enableCors(boolean enableCors) { + this.enableCors(new CorsConfiger(), enableCors); + return this; + } + + /** + * Set whether to config cors + * @param corsConfig config cors + * @param enableCors enable cors + * @return blade + */ + public Blade enableCors(CorsConfiger corsConfig, boolean enableCors) { this.environment.set(ENV_KEY_CORS_ENABLE, enableCors); if (enableCors) { - this.use(new CorsMiddleware()); + this.use(new CorsMiddleware(corsConfig)); } return this; } diff --git a/src/main/java/com/blade/security/web/cors/CorsConfiger.java b/src/main/java/com/blade/security/web/cors/CorsConfiger.java new file mode 100644 index 000000000..b7bb3c849 --- /dev/null +++ b/src/main/java/com/blade/security/web/cors/CorsConfiger.java @@ -0,0 +1,39 @@ +package com.blade.security.web.cors; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author PSH + * Date: 2018/10/29 + */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Builder +public class CorsConfiger { + + public static final String ALL = "*"; + + public static final String DEFAULT_ALLOWED_HEADERS = "Origin, X-Requested-With, Content-Type," + + " Accept, Connection, User-Agent, Cookie, Cache-Control, token"; + + public static final String DEFAULT_ALLOWED_METHODS = "GET, OPTIONS, HEAD, PUT, POST, DELETE"; + + public static final String DEFAULT_ALLOW_CREDENTIALS = "true"; + + public static final Long DEFAULT_MAX_AGE = 1800L; + + + private List allowedMethods; + + private List allowedHeaders; + + private Long maxAge; + + private Boolean allowCredentials; + +} 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 db7ba040a..75cc3a50e 100644 --- a/src/main/java/com/blade/security/web/cors/CorsMiddleware.java +++ b/src/main/java/com/blade/security/web/cors/CorsMiddleware.java @@ -2,6 +2,12 @@ import com.blade.mvc.RouteContext; import com.blade.mvc.hook.WebHook; +import com.blade.mvc.http.Request; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.util.internal.StringUtil; +import java.util.StringJoiner; +import java.util.stream.Collector; +import lombok.extern.slf4j.Slf4j; /** * CorsMiddleware @@ -9,18 +15,80 @@ * @author biezhi * @date 2018/7/11 */ +@Slf4j public class CorsMiddleware implements WebHook { + private CorsConfiger corsConfig; + + public CorsMiddleware() { + } + + public CorsMiddleware(CorsConfiger corsConfiger) { + this.corsConfig = corsConfiger; + } + @Override public boolean before(RouteContext context) { - context.header("Access-Control-Allow-Origin", "*"); - context.header("Access-Control-Allow-Credential", "true"); - context.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Connection, User-Agent, Cookie, Cache-Control"); - context.header("Access-Control-Allow-Methods", "GET, OPTIONS, HEAD, PUT, POST, DELETE"); + this.allowCredentials(context) + .allowMethods(context) + .allowOrigin(context) + .setMaxAge(context) + .allowCredentials(context); if ("OPTIONS".equals(context.method())) { context.status(202); } return true; } + private CorsMiddleware allowOrigin(RouteContext context) { + Request request = context.request(); + String originUrl = request.header(HttpHeaderNames.ORIGIN.toString()); + if (StringUtil.isNullOrEmpty(originUrl)) { + originUrl = CorsConfiger.ALL; + } + context.header("Access-Control-Allow-Headers", originUrl); + return this; + } + + private CorsMiddleware allowMethods(RouteContext context) { + if (corsConfig == null || corsConfig.getAllowedMethods() == null + || corsConfig.getAllowedMethods().size() == 0) { + + context.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 + )); + context.response().header("Access-Control-Allow-Methods", methods); + return this; + } + + private CorsMiddleware allowCredentials(RouteContext context) { + if (corsConfig == null || corsConfig.getAllowCredentials() == null) { + context.header("Access-Control-Allow-Credentials", + CorsConfiger.DEFAULT_ALLOW_CREDENTIALS); + return this; + } + context.response().header("Access-Control-Allow-Credentials", + corsConfig.getAllowCredentials().toString()); + return this; + } + + private CorsMiddleware setMaxAge(RouteContext context) { + + if (corsConfig == null || corsConfig.getMaxAge() == null) { + context.response().header("Access-Control-Max-Age", + CorsConfiger.DEFAULT_MAX_AGE.toString()); + return this; + } + context.header(HttpHeaderNames.ACCESS_CONTROL_MAX_AGE.toString(), corsConfig.getMaxAge().toString()); + return this; + } + } From 79cfbb68c2d3e5b0c3e9826a23ed30eb113f8def Mon Sep 17 00:00:00 2001 From: crossoverJie Date: Fri, 16 Nov 2018 13:51:41 +0800 Subject: [PATCH 02/21] :bug: Fix #289 --- src/main/java/com/blade/Blade.java | 1 + src/main/java/com/blade/kit/Assert.java | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/main/java/com/blade/Blade.java b/src/main/java/com/blade/Blade.java index 50bd6168b..e9814b515 100644 --- a/src/main/java/com/blade/Blade.java +++ b/src/main/java/com/blade/Blade.java @@ -857,6 +857,7 @@ public Blade start(Class mainCls, String... args) { */ public Blade start(Class bootClass, @NonNull String address, int port, String... args) { try { + Assert.packageNotEmpty(bootClass,"your main class is empty of package."); this.loadConfig(args); this.environment.set(ENV_KEY_SERVER_ADDRESS, address); diff --git a/src/main/java/com/blade/kit/Assert.java b/src/main/java/com/blade/kit/Assert.java index e393e77b3..b2332d22f 100644 --- a/src/main/java/com/blade/kit/Assert.java +++ b/src/main/java/com/blade/kit/Assert.java @@ -61,4 +61,10 @@ public static T wrap(Callable callable) { } } + public static void packageNotEmpty(Class clazz,String msg){ + if (clazz.getPackage() == null) { + throw new IllegalArgumentException("[" + clazz.getName() + ".java] " + msg); + } + } + } From 034dc4577a53087060ef1811ae01fb46653e3f94 Mon Sep 17 00:00:00 2001 From: psh686868 Date: Sat, 17 Nov 2018 14:03:19 +0800 Subject: [PATCH 03/21] =?UTF-8?q?:art:=20=E6=B7=BB=E5=8A=A0StringKit?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/blade/kit/StringKit.java | 86 +++++++++++++++++++--- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/blade/kit/StringKit.java b/src/main/java/com/blade/kit/StringKit.java index 00b74e949..0b30bc0e5 100644 --- a/src/main/java/com/blade/kit/StringKit.java +++ b/src/main/java/com/blade/kit/StringKit.java @@ -1,6 +1,9 @@ package com.blade.kit; import com.blade.mvc.multipart.MimeType; +import java.util.function.Function; +import java.util.function.Supplier; +import lombok.NonNull; import lombok.experimental.UtilityClass; import java.util.Random; @@ -72,11 +75,79 @@ public static boolean isNotBlank(String... str) { * @param consumer consumer */ public static void isNotBlankThen(String str, Consumer consumer) { - if (!isBlank(str)) { + notBankAccept(str, Function.identity(), consumer); + } + + /** + * Execute consumer when the string is empty + * + * @param str string value + * @param consumer consumer + */ + public static void isBlankThen(String str, Consumer consumer) { + if (isBlank(str)) { consumer.accept(str); } } + + /** + * + * we can replace + * ` + * if(StringUtils.isNotBlank(str)) { + * Integer i = Integer.parseInt (str) + * demo.setAge(i) + * } + * ` + * with + * ` + * notBankAccept ("2", Integer::parseInt, route::setSort) + * ` + * @param str string value + * @param consumer consumer + * @param function format + */ + + public static void notBankAccept(String str, Function function, Consumer consumer) { + if (isNotBlank(str)) { + R r = function.apply(str); + consumer.accept(r); + } + } + + /** + * Execute action when String is not empty + * @param str String value + * @param action action + */ + public static void notBankThen(String str, Runnable action) { + if (isNotBlank(str)) { + action.run(); + } + } + + /** + * we can replace + * if(doMethod1()!= null) { + * return doMethod1() + * } else { + * return doMethod2() + * } + * with + * return notBlankElse(bar::getName, bar::getNickName) + * @param s1 Supplier + * @param s2 Supplier + */ + + public static T noNullElseGet(@NonNull Supplier s1, @NonNull Supplier s2) { + T t1 = s1.get(); + if (t1 != null) { + return t1; + } + return s2.get(); + } + /** * Determine whether a string is blank * @@ -95,17 +166,6 @@ public static boolean isNotEmpty(String str) { return !isEmpty(str); } - /** - * Execute consumer when the string is empty - * - * @param str string value - * @param consumer consumer - */ - public static void isBlankThen(String str, Consumer consumer) { - if (isBlank(str)) { - consumer.accept(str); - } - } /** * There is at least one null in the array of strings @@ -153,6 +213,8 @@ public static String alignLeft(Object o, int width, char c) { return s + dup(c, width - length); } + + /** * Fill a certain number of special characters on the left side of the string * From 900d7182b6233475cc9885783147d2b97c42c0f3 Mon Sep 17 00:00:00 2001 From: psh686868 Date: Sat, 17 Nov 2018 14:04:42 +0800 Subject: [PATCH 04/21] =?UTF-8?q?:art:=20=E6=B5=8B=E8=AF=95StringKit?= =?UTF-8?q?=E6=96=B0=E5=8A=A0=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/blade/kit/StringKitTest.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/test/java/com/blade/kit/StringKitTest.java b/src/test/java/com/blade/kit/StringKitTest.java index 156ab27af..41689f413 100644 --- a/src/test/java/com/blade/kit/StringKitTest.java +++ b/src/test/java/com/blade/kit/StringKitTest.java @@ -30,6 +30,23 @@ public void testIsBlank() { Assert.assertEquals(true,StringKit.isNotBlank("a","b","c")); Assert.assertEquals(true,StringKit.isNotBlank("abc","d ef","gh i")); + Bar bar = new Bar(); + StringKit.isNotBlankThen("barName", bar::setName); + Assert.assertEquals("barName", bar.getName()); + + StringKit.notBankAccept("1", Integer::parseInt, bar::setAge); + Assert.assertEquals(1, bar.getAge()); + + StringKit.notBankThen("bar", bar::doSameThing); + + bar.setName("bar"); + Foo foo = new Foo(); + String name = StringKit.noNullElseGet(foo::getName, bar::getName); + Assert.assertEquals("bar", name); + + foo.setName("foo"); + String fooName = StringKit.noNullElseGet(foo::getName, bar::getName); + Assert.assertEquals("foo", fooName); } @Test @@ -126,4 +143,42 @@ public void testToCapitalizeCamelCase(){ Assert.assertEquals("UserNameAge", StringKit.toCapitalizeCamelCase(b)); } + class Bar { + String name; + int age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public void doSameThing() { + System.out.println("do same thing"); + } + } + + class Foo { + String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + } From d28e444e0f95f3d8fd6b9f3054459fe86902bbb9 Mon Sep 17 00:00:00 2001 From: psh686868 Date: Sat, 17 Nov 2018 20:13:09 +0800 Subject: [PATCH 05/21] :update: update StringKitTest --- src/test/java/com/blade/kit/StringKitTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/blade/kit/StringKitTest.java b/src/test/java/com/blade/kit/StringKitTest.java index 41689f413..99aba9003 100644 --- a/src/test/java/com/blade/kit/StringKitTest.java +++ b/src/test/java/com/blade/kit/StringKitTest.java @@ -144,8 +144,8 @@ public void testToCapitalizeCamelCase(){ } class Bar { - String name; - int age; + private String name; + private int age; public String getName() { return name; @@ -169,7 +169,7 @@ public void doSameThing() { } class Foo { - String name; + private String name; public String getName() { return name; From fb8ba584e700f97f7c0b99892fb45fc305fb2019 Mon Sep 17 00:00:00 2001 From: biezhi Date: Wed, 21 Nov 2018 14:16:39 +0800 Subject: [PATCH 06/21] :sparkles: resolve #238 --- src/main/java/com/blade/ioc/SimpleIoc.java | 9 ++++++--- .../java/com/blade/ioc/annotation/Bean.java | 2 ++ .../java/com/blade/ioc/bean/BeanDefine.java | 17 ++++++++--------- src/test/java/com/blade/ioc/BeanDefineTest.java | 8 ++++---- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/blade/ioc/SimpleIoc.java b/src/main/java/com/blade/ioc/SimpleIoc.java index 348e5f07e..e6c366249 100644 --- a/src/main/java/com/blade/ioc/SimpleIoc.java +++ b/src/main/java/com/blade/ioc/SimpleIoc.java @@ -1,5 +1,6 @@ package com.blade.ioc; +import com.blade.ioc.annotation.Bean; import com.blade.ioc.bean.BeanDefine; import lombok.extern.slf4j.Slf4j; @@ -59,7 +60,9 @@ public void setBean(Class type, Object proxyBean) { */ @Override public T addBean(Class type) { - Object bean = addBean(type, true); + Bean beanAnnotation = type.getAnnotation(Bean.class); + boolean isSingleton = null == beanAnnotation || beanAnnotation.prototype(); + Object bean = addBean(type, isSingleton); return type.cast(bean); } @@ -163,7 +166,7 @@ private Object addBean(String name, Class beanClass, boolean singleton) { } } - return beanDefine.getBean(); + return Objects.requireNonNull(beanDefine).getBean(); } private BeanDefine getBeanDefine(Class beanClass, boolean singleton) { @@ -171,7 +174,7 @@ private BeanDefine getBeanDefine(Class beanClass, boolean singleton) { Object object = beanClass.newInstance(); return new BeanDefine(object, beanClass, singleton); } catch (InstantiationException | IllegalAccessException e) { - e.printStackTrace(); + log.error("get BeanDefine error", e); } return null; } diff --git a/src/main/java/com/blade/ioc/annotation/Bean.java b/src/main/java/com/blade/ioc/annotation/Bean.java index 541b4419e..526548df6 100644 --- a/src/main/java/com/blade/ioc/annotation/Bean.java +++ b/src/main/java/com/blade/ioc/annotation/Bean.java @@ -15,4 +15,6 @@ String value() default ""; + boolean prototype() default false; + } \ No newline at end of file diff --git a/src/main/java/com/blade/ioc/bean/BeanDefine.java b/src/main/java/com/blade/ioc/bean/BeanDefine.java index d3668f90c..e3b9c70c7 100644 --- a/src/main/java/com/blade/ioc/bean/BeanDefine.java +++ b/src/main/java/com/blade/ioc/bean/BeanDefine.java @@ -10,7 +10,7 @@ public class BeanDefine { private Object bean; private Class type; - private boolean isSingle; + private boolean prototype; public BeanDefine(Object bean) { this(bean, bean.getClass()); @@ -19,13 +19,13 @@ public BeanDefine(Object bean) { public BeanDefine(Object bean, Class type) { this.bean = bean; this.type = type; - this.isSingle = true; + this.prototype = true; } - public BeanDefine(Object bean, Class type, boolean isSingle) { + public BeanDefine(Object bean, Class type, boolean prototype) { this.bean = bean; this.type = type; - this.isSingle = isSingle; + this.prototype = prototype; } public Object getBean() { @@ -44,12 +44,11 @@ public void setType(Class type) { this.type = type; } - public boolean isSingle() { - return isSingle; + public boolean isPrototype() { + return prototype; } - public void setSignle(boolean isSingle) { - this.isSingle = isSingle; + public void setPrototype(boolean prototype) { + this.prototype = prototype; } - } \ No newline at end of file diff --git a/src/test/java/com/blade/ioc/BeanDefineTest.java b/src/test/java/com/blade/ioc/BeanDefineTest.java index b572c631b..286358206 100644 --- a/src/test/java/com/blade/ioc/BeanDefineTest.java +++ b/src/test/java/com/blade/ioc/BeanDefineTest.java @@ -21,15 +21,15 @@ public void testBeanDefine() { Object bean = beanDefine.getBean(); assertNotNull(bean); - assertEquals(true, beanDefine.isSingle()); + assertEquals(true, beanDefine.isPrototype()); - beanDefine.setSignle(true); + beanDefine.setPrototype(true); beanDefine.setType(BladeBeanDefineType.class); beanDefine.setBean(new BladeBeanDefineType()); assertEquals(BladeBeanDefineType.class, type); assertNotNull(bean); - assertEquals(true, beanDefine.isSingle()); + assertEquals(true, beanDefine.isPrototype()); } @@ -40,7 +40,7 @@ public void testBeanDefine2() { beanDefine = new BeanDefine(new BladeBeanDefineType(), BladeBeanDefineType.class, true); assertEquals(BladeBeanDefineType.class, beanDefine.getType()); - assertEquals(true, beanDefine.isSingle()); + assertEquals(true, beanDefine.isPrototype()); } } From f35e1e2951fc682ec9abbc2bf2b388cf5c0fc984 Mon Sep 17 00:00:00 2001 From: biezhi Date: Wed, 21 Nov 2018 14:18:58 +0800 Subject: [PATCH 07/21] :sparkles: resolve #238 --- src/main/java/com/blade/ioc/SimpleIoc.java | 16 ++++++++-------- src/main/java/com/blade/ioc/bean/BeanDefine.java | 15 ++++++++------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/blade/ioc/SimpleIoc.java b/src/main/java/com/blade/ioc/SimpleIoc.java index e6c366249..583624dac 100644 --- a/src/main/java/com/blade/ioc/SimpleIoc.java +++ b/src/main/java/com/blade/ioc/SimpleIoc.java @@ -61,8 +61,8 @@ public void setBean(Class type, Object proxyBean) { @Override public T addBean(Class type) { Bean beanAnnotation = type.getAnnotation(Bean.class); - boolean isSingleton = null == beanAnnotation || beanAnnotation.prototype(); - Object bean = addBean(type, isSingleton); + boolean isPrototype = null == beanAnnotation || beanAnnotation.prototype(); + Object bean = addBean(type, isPrototype); return type.cast(bean); } @@ -141,15 +141,15 @@ private void addBean(String name, BeanDefine beanDefine) { /** * Register @Bean marked objects */ - private Object addBean(Class type, boolean singleton) { - return addBean(type.getName(), type, singleton); + private Object addBean(Class type, boolean isPrototype) { + return addBean(type.getName(), type, isPrototype); } /** * Register @Bean marked objects */ - private Object addBean(String name, Class beanClass, boolean singleton) { - BeanDefine beanDefine = this.getBeanDefine(beanClass, singleton); + private Object addBean(String name, Class beanClass, boolean isPrototype) { + BeanDefine beanDefine = this.getBeanDefine(beanClass, isPrototype); if (pool.put(name, beanDefine) != null) { log.warn("Duplicated Bean: {}", name); @@ -169,10 +169,10 @@ private Object addBean(String name, Class beanClass, boolean singleton) { return Objects.requireNonNull(beanDefine).getBean(); } - private BeanDefine getBeanDefine(Class beanClass, boolean singleton) { + private BeanDefine getBeanDefine(Class beanClass, boolean isPrototype) { try { Object object = beanClass.newInstance(); - return new BeanDefine(object, beanClass, singleton); + return new BeanDefine(object, beanClass, isPrototype); } catch (InstantiationException | IllegalAccessException e) { log.error("get BeanDefine error", e); } diff --git a/src/main/java/com/blade/ioc/bean/BeanDefine.java b/src/main/java/com/blade/ioc/bean/BeanDefine.java index e3b9c70c7..db8d92550 100644 --- a/src/main/java/com/blade/ioc/bean/BeanDefine.java +++ b/src/main/java/com/blade/ioc/bean/BeanDefine.java @@ -10,7 +10,7 @@ public class BeanDefine { private Object bean; private Class type; - private boolean prototype; + private boolean isPrototype; public BeanDefine(Object bean) { this(bean, bean.getClass()); @@ -19,13 +19,13 @@ public BeanDefine(Object bean) { public BeanDefine(Object bean, Class type) { this.bean = bean; this.type = type; - this.prototype = true; + this.isPrototype = true; } - public BeanDefine(Object bean, Class type, boolean prototype) { + public BeanDefine(Object bean, Class type, boolean isPrototype) { this.bean = bean; this.type = type; - this.prototype = prototype; + this.isPrototype = isPrototype; } public Object getBean() { @@ -45,10 +45,11 @@ public void setType(Class type) { } public boolean isPrototype() { - return prototype; + return isPrototype; } - public void setPrototype(boolean prototype) { - this.prototype = prototype; + public void setPrototype(boolean isPrototype) { + this.isPrototype = isPrototype; } + } \ No newline at end of file From aaa31785596d3bda522c19e8fc352f9b963da922 Mon Sep 17 00:00:00 2001 From: biezhi Date: Wed, 21 Nov 2018 14:26:03 +0800 Subject: [PATCH 08/21] :bug: fixed boot class not initialize --- src/main/java/com/blade/Blade.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/blade/Blade.java b/src/main/java/com/blade/Blade.java index 240c0b7e2..ee9f8a2c3 100644 --- a/src/main/java/com/blade/Blade.java +++ b/src/main/java/com/blade/Blade.java @@ -849,7 +849,7 @@ public Blade start() { */ public Blade start(Class mainCls, String... args) { try { - Assert.packageNotEmpty(bootClass,"your main class is empty of package."); + Assert.packageNotEmpty(mainCls,"your main class is empty of package."); this.loadConfig(args); this.bootClass = mainCls; From 33fb823694fd78320a727435e6c321886a9788ff Mon Sep 17 00:00:00 2001 From: biezhi Date: Wed, 21 Nov 2018 16:05:59 +0800 Subject: [PATCH 09/21] :sparkles: resolve #238 --- src/main/java/com/blade/ioc/Ioc.java | 2 + src/main/java/com/blade/ioc/SimpleIoc.java | 47 ++++--- .../java/com/blade/ioc/annotation/Bean.java | 2 +- .../java/com/blade/ioc/annotation/Inject.java | 2 + .../java/com/blade/ioc/bean/BeanDefine.java | 26 ++-- .../java/com/blade/ioc/bean/ClassDefine.java | 12 +- .../com/blade/ioc/bean/FieldInjector.java | 5 + src/main/java/com/blade/kit/BladeKit.java | 71 ---------- src/main/java/com/blade/kit/IocKit.java | 132 ++++++++++++++++++ src/main/java/com/blade/mvc/RouteContext.java | 11 ++ .../java/com/blade/mvc/annotation/Path.java | 6 + .../com/blade/mvc/route/RouteBuilder.java | 4 +- .../com/blade/server/netty/NettyServer.java | 24 ++-- .../server/netty/RouteMethodHandler.java | 12 +- .../java/com/blade/ioc/BeanDefineTest.java | 8 +- .../com/blade/mvc/route/RouteBuilderTest.java | 2 +- src/test/java/netty_hello/DemoController.java | 7 +- 17 files changed, 241 insertions(+), 132 deletions(-) create mode 100644 src/main/java/com/blade/kit/IocKit.java diff --git a/src/main/java/com/blade/ioc/Ioc.java b/src/main/java/com/blade/ioc/Ioc.java index 7e7d14510..8cc6fde81 100644 --- a/src/main/java/com/blade/ioc/Ioc.java +++ b/src/main/java/com/blade/ioc/Ioc.java @@ -37,6 +37,8 @@ public interface Ioc { */ T addBean(Class type); + Object createBean(Class type); + /** * Set bean, e.g aop proxy * diff --git a/src/main/java/com/blade/ioc/SimpleIoc.java b/src/main/java/com/blade/ioc/SimpleIoc.java index 583624dac..bb2215932 100644 --- a/src/main/java/com/blade/ioc/SimpleIoc.java +++ b/src/main/java/com/blade/ioc/SimpleIoc.java @@ -2,6 +2,8 @@ import com.blade.ioc.annotation.Bean; import com.blade.ioc.bean.BeanDefine; +import com.blade.kit.IocKit; +import com.blade.mvc.WebContext; import lombok.extern.slf4j.Slf4j; import java.util.*; @@ -31,12 +33,12 @@ public void addBean(Object bean) { @Override public void addBean(String name, Object bean) { BeanDefine beanDefine = new BeanDefine(bean); - addBean(name, beanDefine); - // add interface + put(name, beanDefine); + // add interface、put to pool Class[] interfaces = beanDefine.getType().getInterfaces(); if (interfaces.length > 0) { for (Class interfaceClazz : interfaces) { - this.addBean(interfaceClazz.getName(), beanDefine); + this.put(interfaceClazz.getName(), beanDefine); } } } @@ -61,9 +63,20 @@ public void setBean(Class type, Object proxyBean) { @Override public T addBean(Class type) { Bean beanAnnotation = type.getAnnotation(Bean.class); - boolean isPrototype = null == beanAnnotation || beanAnnotation.prototype(); - Object bean = addBean(type, isPrototype); - return type.cast(bean); + boolean isSingleton = null == beanAnnotation || beanAnnotation.singleton(); + if (isSingleton) { + Object bean = put(type, true); + return type.cast(bean); + } + return null; + } + + @Override + public Object createBean(Class type) { + BeanDefine beanDefine = createBeanDefine(type, true); + IocKit.injection(this, Objects.requireNonNull(beanDefine)); + IocKit.injectionValue(WebContext.blade().environment(), beanDefine); + return beanDefine.getBean(); } @Override @@ -72,7 +85,7 @@ public T getBean(Class type) { try { return type.cast(bean); } catch (Exception e) { - e.printStackTrace(); + log.error("get bean error", e); } return null; } @@ -93,7 +106,7 @@ public List getBeanDefines() { @Override public BeanDefine getBeanDefine(Class type) { - return this.getBeanDefine(type, true); + return pool.get(type.getName()); } @Override @@ -132,7 +145,7 @@ public void clearAll() { /** * Add user-defined objects */ - private void addBean(String name, BeanDefine beanDefine) { + private void put(String name, BeanDefine beanDefine) { if (pool.put(name, beanDefine) != null) { log.warn("Duplicated Bean: {}", name); } @@ -141,38 +154,38 @@ private void addBean(String name, BeanDefine beanDefine) { /** * Register @Bean marked objects */ - private Object addBean(Class type, boolean isPrototype) { - return addBean(type.getName(), type, isPrototype); + private Object put(Class type, boolean isSingleton) { + return put(type.getName(), type, isSingleton); } /** * Register @Bean marked objects */ - private Object addBean(String name, Class beanClass, boolean isPrototype) { - BeanDefine beanDefine = this.getBeanDefine(beanClass, isPrototype); + private Object put(String name, Class beanClass, boolean isSingleton) { + BeanDefine beanDefine = this.createBeanDefine(beanClass, isSingleton); if (pool.put(name, beanDefine) != null) { log.warn("Duplicated Bean: {}", name); } - // add interface + // add interface、put to pool Class[] interfaces = beanClass.getInterfaces(); if (interfaces.length > 0) { for (Class interfaceClazz : interfaces) { if (null != this.getBean(interfaceClazz)) { break; } - this.addBean(interfaceClazz.getName(), beanDefine); + this.put(interfaceClazz.getName(), beanDefine); } } return Objects.requireNonNull(beanDefine).getBean(); } - private BeanDefine getBeanDefine(Class beanClass, boolean isPrototype) { + private BeanDefine createBeanDefine(Class beanClass, boolean isSingleton) { try { Object object = beanClass.newInstance(); - return new BeanDefine(object, beanClass, isPrototype); + return new BeanDefine(object, beanClass, isSingleton); } catch (InstantiationException | IllegalAccessException e) { log.error("get BeanDefine error", e); } diff --git a/src/main/java/com/blade/ioc/annotation/Bean.java b/src/main/java/com/blade/ioc/annotation/Bean.java index 526548df6..267d4a8cc 100644 --- a/src/main/java/com/blade/ioc/annotation/Bean.java +++ b/src/main/java/com/blade/ioc/annotation/Bean.java @@ -15,6 +15,6 @@ String value() default ""; - boolean prototype() default false; + 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 eb424c0cd..052c501f3 100644 --- a/src/main/java/com/blade/ioc/annotation/Inject.java +++ b/src/main/java/com/blade/ioc/annotation/Inject.java @@ -17,4 +17,6 @@ String value() default ""; + boolean singleton() default true; + } \ No newline at end of file diff --git a/src/main/java/com/blade/ioc/bean/BeanDefine.java b/src/main/java/com/blade/ioc/bean/BeanDefine.java index db8d92550..76ec7ada4 100644 --- a/src/main/java/com/blade/ioc/bean/BeanDefine.java +++ b/src/main/java/com/blade/ioc/bean/BeanDefine.java @@ -8,9 +8,10 @@ */ public class BeanDefine { - private Object bean; + private Object bean; private Class type; - private boolean isPrototype; + private boolean isSingleton; + private boolean hasPrototypeField; public BeanDefine(Object bean) { this(bean, bean.getClass()); @@ -19,13 +20,13 @@ public BeanDefine(Object bean) { public BeanDefine(Object bean, Class type) { this.bean = bean; this.type = type; - this.isPrototype = true; + this.isSingleton = true; } - public BeanDefine(Object bean, Class type, boolean isPrototype) { + public BeanDefine(Object bean, Class type, boolean isSingleton) { this.bean = bean; this.type = type; - this.isPrototype = isPrototype; + this.isSingleton = isSingleton; } public Object getBean() { @@ -44,12 +45,19 @@ public void setType(Class type) { this.type = type; } - public boolean isPrototype() { - return isPrototype; + public boolean isSingleton() { + return isSingleton; } - public void setPrototype(boolean isPrototype) { - this.isPrototype = isPrototype; + public void setSingleton(boolean isSingleton) { + this.isSingleton = isSingleton; } + public boolean isHasPrototypeField() { + return hasPrototypeField; + } + + public void setHasPrototypeField(boolean hasPrototypeField) { + this.hasPrototypeField = hasPrototypeField; + } } \ No newline at end of file diff --git a/src/main/java/com/blade/ioc/bean/ClassDefine.java b/src/main/java/com/blade/ioc/bean/ClassDefine.java index dc2215f67..bb83dd221 100644 --- a/src/main/java/com/blade/ioc/bean/ClassDefine.java +++ b/src/main/java/com/blade/ioc/bean/ClassDefine.java @@ -10,7 +10,7 @@ public final class ClassDefine { - private static final ConcurrentHashMap, ClassDefine> pool = new ConcurrentHashMap, ClassDefine>(128); + private static final ConcurrentHashMap, ClassDefine> pool = new ConcurrentHashMap<>(128); private final Class clazz; @@ -54,13 +54,12 @@ public List getInterfaces() { return Collections.emptyList(); } List results = new ArrayList<>(interfaces.length); - for (Class intf : interfaces) { - results.add(ClassDefine.create(intf)); + for (Class interface_ : interfaces) { + results.add(ClassDefine.create(interface_)); } return results; } - // ------------------------------------------------------------------ public Annotation[] getAnnotations() { return clazz.getAnnotations(); } @@ -69,15 +68,10 @@ public T getAnnotation(Class annotationClass) { return clazz.getAnnotation(annotationClass); } - public boolean isAnnotationPresent(Class annotationClass) { - return clazz.isAnnotationPresent(annotationClass); - } - public Field[] getDeclaredFields() { return clazz.getDeclaredFields(); } - // ------------------------------------------------------------------ public int getModifiers() { return clazz.getModifiers(); } diff --git a/src/main/java/com/blade/ioc/bean/FieldInjector.java b/src/main/java/com/blade/ioc/bean/FieldInjector.java index 9ddf81847..ecbc3415b 100644 --- a/src/main/java/com/blade/ioc/bean/FieldInjector.java +++ b/src/main/java/com/blade/ioc/bean/FieldInjector.java @@ -2,6 +2,7 @@ import com.blade.ioc.Injector; import com.blade.ioc.Ioc; +import com.blade.kit.IocKit; import java.lang.reflect.Field; @@ -21,6 +22,10 @@ public FieldInjector(Ioc ioc, Field field) { this.field = field; } + public boolean isSingleton() { + return IocKit.isSingleton(field.getType()); + } + @Override public void injection(Object bean) { try { diff --git a/src/main/java/com/blade/kit/BladeKit.java b/src/main/java/com/blade/kit/BladeKit.java index 13a15d9e4..229c25c11 100644 --- a/src/main/java/com/blade/kit/BladeKit.java +++ b/src/main/java/com/blade/kit/BladeKit.java @@ -15,15 +15,6 @@ */ package com.blade.kit; -import com.blade.Environment; -import com.blade.ioc.Ioc; -import com.blade.ioc.annotation.Inject; -import com.blade.ioc.annotation.InjectWith; -import com.blade.ioc.annotation.Value; -import com.blade.ioc.bean.BeanDefine; -import com.blade.ioc.bean.ClassDefine; -import com.blade.ioc.bean.FieldInjector; -import com.blade.ioc.bean.ValueInjector; import com.blade.mvc.Const; import com.blade.mvc.http.HttpMethod; import com.blade.mvc.route.Route; @@ -37,7 +28,6 @@ import java.io.UnsupportedEncodingException; import java.lang.invoke.SerializedLambda; import java.lang.management.ManagementFactory; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; @@ -64,67 +54,6 @@ public class BladeKit { isWindows = System.getProperties().getProperty("os.name").toLowerCase().contains("win"); } - /** - * Get @Inject Annotated field - * - * @param ioc ioc container - * @param classDefine classDefine - * @return return FieldInjector - */ - private static List getInjectFields(Ioc ioc, ClassDefine classDefine) { - List injectors = new ArrayList<>(8); - for (Field field : classDefine.getDeclaredFields()) { - if (null != field.getAnnotation(InjectWith.class) || null != field.getAnnotation(Inject.class)) { - injectors.add(new FieldInjector(ioc, field)); - } - } - if (injectors.size() == 0) { - return new ArrayList<>(); - } - return injectors; - } - - /** - * Get @Value Annotated field - * - * @param environment - * @param classDefine - * @return - */ - private static List getValueInjectFields(Environment environment, ClassDefine classDefine) { - List valueInjectors = new ArrayList<>(8); - //handle class annotation - if (null != classDefine.getType().getAnnotation(Value.class)) { - String suffix = classDefine.getType().getAnnotation(Value.class).name(); - Arrays.stream(classDefine.getDeclaredFields()).forEach(field -> valueInjectors.add( - new ValueInjector(environment, field, suffix + "." + field.getName()) - )); - } else { - Arrays.stream(classDefine.getDeclaredFields()). - filter(field -> null != field.getAnnotation(Value.class)). - map(field -> new ValueInjector( - environment, field, field.getAnnotation(Value.class).name()) - ).forEach(valueInjectors::add); - } - return valueInjectors; - } - - public static void injection(Ioc ioc, BeanDefine beanDefine) { - ClassDefine classDefine = ClassDefine.create(beanDefine.getType()); - List fieldInjectors = getInjectFields(ioc, classDefine); - Object bean = beanDefine.getBean(); - for (FieldInjector fieldInjector : fieldInjectors) { - fieldInjector.injection(bean); - } - } - - public static void injectionValue(Environment environment, BeanDefine beanDefine) { - ClassDefine classDefine = ClassDefine.create(beanDefine.getType()); - List valueFields = getValueInjectFields(environment, classDefine); - Object bean = beanDefine.getBean(); - valueFields.stream().forEach(fieldInjector -> fieldInjector.injection(bean)); - } - public static String getLambdaFieldName(Serializable lambda) { for (Class cl = lambda.getClass(); cl != null; cl = cl.getSuperclass()) { try { diff --git a/src/main/java/com/blade/kit/IocKit.java b/src/main/java/com/blade/kit/IocKit.java new file mode 100644 index 000000000..f6eb0d2bb --- /dev/null +++ b/src/main/java/com/blade/kit/IocKit.java @@ -0,0 +1,132 @@ +/** + * Copyright (c) 2017, biezhi 王爵 (biezhi.me@gmail.com) + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.blade.kit; + +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; +import com.blade.ioc.bean.BeanDefine; +import com.blade.ioc.bean.ClassDefine; +import com.blade.ioc.bean.FieldInjector; +import com.blade.ioc.bean.ValueInjector; +import com.blade.mvc.annotation.Path; +import lombok.experimental.UtilityClass; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Ioc kit + * + * @author biezhi + * 2017/5/31 + */ +@UtilityClass +public class IocKit { + + /** + * Get @Inject Annotated field + * + * @param ioc ioc container + * @param classDefine classDefine + * @return return FieldInjector + */ + private static List getInjectFields(Ioc ioc, ClassDefine classDefine) { + List injectors = new ArrayList<>(8); + for (Field field : classDefine.getDeclaredFields()) { + if (null != field.getAnnotation(InjectWith.class) || null != field.getAnnotation(Inject.class)) { + injectors.add(new FieldInjector(ioc, field)); + } + } + if (injectors.size() == 0) { + return new ArrayList<>(); + } + return injectors; + } + + /** + * Get @Value Annotated field + * + * @param environment + * @param classDefine + * @return + */ + private static List getValueInjectFields(Environment environment, ClassDefine classDefine) { + List valueInjectors = new ArrayList<>(8); + //handle class annotation + if (null != classDefine.getType().getAnnotation(Value.class)) { + String suffix = classDefine.getType().getAnnotation(Value.class).name(); + Arrays.stream(classDefine.getDeclaredFields()).forEach(field -> valueInjectors.add( + new ValueInjector(environment, field, suffix + "." + field.getName()) + )); + } else { + Arrays.stream(classDefine.getDeclaredFields()). + filter(field -> null != field.getAnnotation(Value.class)). + map(field -> new ValueInjector( + environment, field, field.getAnnotation(Value.class).name()) + ).forEach(valueInjectors::add); + } + return valueInjectors; + } + + public static void injection(Ioc ioc, BeanDefine beanDefine) { + ClassDefine classDefine = ClassDefine.create(beanDefine.getType()); + List fieldInjectors = getInjectFields(ioc, classDefine); + + Object bean = beanDefine.getBean(); + + AtomicBoolean hasPrototypeField = new AtomicBoolean(false); + + fieldInjectors.stream().filter(FieldInjector::isSingleton).forEach(fieldInjector -> { + fieldInjector.injection(bean); + hasPrototypeField.set(true); + }); + + beanDefine.setHasPrototypeField(hasPrototypeField.get()); + } + + public static void injectionValue(Environment environment, BeanDefine beanDefine) { + ClassDefine classDefine = ClassDefine.create(beanDefine.getType()); + List valueFields = getValueInjectFields(environment, classDefine); + + Object bean = beanDefine.getBean(); + + valueFields.forEach(fieldInjector -> fieldInjector.injection(bean)); + } + + 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/RouteContext.java b/src/main/java/com/blade/mvc/RouteContext.java index 9c0011358..505d9c23b 100644 --- a/src/main/java/com/blade/mvc/RouteContext.java +++ b/src/main/java/com/blade/mvc/RouteContext.java @@ -15,6 +15,7 @@ */ package com.blade.mvc; +import com.blade.kit.IocKit; import com.blade.mvc.http.Body; import com.blade.mvc.http.Request; import com.blade.mvc.http.Response; @@ -522,6 +523,16 @@ public Object[] routeParameters() { public void initRoute(Route route) { this.request.initPathParams(route); this.route = route; + + boolean singleton = IocKit.isSingleton(route.getTargetType()); + + if (singleton) { + 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 d0f7572ac..c0cf6559b 100644 --- a/src/main/java/com/blade/mvc/annotation/Path.java +++ b/src/main/java/com/blade/mvc/annotation/Path.java @@ -31,6 +31,12 @@ */ 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/mvc/route/RouteBuilder.java b/src/main/java/com/blade/mvc/route/RouteBuilder.java index bba7742a4..71311ff6e 100644 --- a/src/main/java/com/blade/mvc/route/RouteBuilder.java +++ b/src/main/java/com/blade/mvc/route/RouteBuilder.java @@ -25,12 +25,11 @@ public RouteBuilder(RouteMatcher routeMatcher) { this.routeMatcher = routeMatcher; } - public void addWebHook(final Class webHook, String pattern, Object hook) { + public void addWebHook(final Class webHook, String pattern) { Method before = ReflectKit.getMethod(webHook, HttpMethod.BEFORE.name().toLowerCase(), RouteContext.class); Method after = ReflectKit.getMethod(webHook, HttpMethod.AFTER.name().toLowerCase(), RouteContext.class); routeMatcher.addRoute(com.blade.mvc.route.Route.builder() - .target(hook) .targetType(webHook) .action(before) .path(pattern) @@ -38,7 +37,6 @@ public void addWebHook(final Class webHook, String pattern, Object hook) { .build()); routeMatcher.addRoute(com.blade.mvc.route.Route.builder() - .target(hook) .targetType(webHook) .action(after) .path(pattern) diff --git a/src/main/java/com/blade/server/netty/NettyServer.java b/src/main/java/com/blade/server/netty/NettyServer.java index 11df9e543..682e4b87e 100644 --- a/src/main/java/com/blade/server/netty/NettyServer.java +++ b/src/main/java/com/blade/server/netty/NettyServer.java @@ -51,9 +51,11 @@ import com.blade.task.cron.CronThreadPoolExecutor; import com.blade.watcher.EnvironmentWatcher; import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.*; +import io.netty.channel.Channel; +import io.netty.channel.DefaultEventLoop; +import io.netty.channel.EventLoop; +import io.netty.channel.EventLoopGroup; import io.netty.channel.epoll.EpollChannelOption; -import io.netty.channel.nio.NioEventLoop; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.ssl.SslContext; @@ -64,7 +66,6 @@ import java.io.File; import java.lang.reflect.Method; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ScheduledFuture; @@ -150,7 +151,7 @@ private void initIoc() { .flatMap(DynamicContext::recursionFindClasses) .map(ClassInfo::getClazz) .filter(ReflectKit::isNormalClass) - .forEach(this::parseCls); + .forEach(this::parseAndCreate); routeMatcher.register(); @@ -166,8 +167,8 @@ private void initIoc() { if (BladeKit.isNotEmpty(beanDefines)) { beanDefines.forEach(b -> { - BladeKit.injection(ioc, b); - BladeKit.injectionValue(environment, b); + IocKit.injection(ioc, b); + IocKit.injectionValue(environment, b); List cronExpressions = BladeKit.getTasks(b.getType()); if (null != cronExpressions) { taskStruts.addAll(cronExpressions); @@ -285,25 +286,26 @@ private void addTask(CronExecutorService executorService, AtomicInteger jobCount } } - private void parseCls(Class clazz) { + private void parseAndCreate(Class clazz) { if (null != clazz.getAnnotation(Bean.class) || null != clazz.getAnnotation(Value.class)) { blade.register(clazz); } if (null != clazz.getAnnotation(Path.class)) { - if (null == blade.ioc().getBean(clazz)) { + Path path = clazz.getAnnotation(Path.class); + if (path.singleton() && null == blade.ioc().getBean(clazz)) { blade.register(clazz); } Object controller = blade.ioc().getBean(clazz); routeBuilder.addRouter(clazz, controller); } + if (ReflectKit.hasInterface(clazz, WebHook.class) && null != clazz.getAnnotation(Bean.class)) { - Object hook = blade.ioc().getBean(clazz); URLPattern URLPattern = clazz.getAnnotation(URLPattern.class); if (null == URLPattern) { - routeBuilder.addWebHook(clazz, "/.*", hook); + routeBuilder.addWebHook(clazz, "/.*"); } else { Stream.of(URLPattern.values()) - .forEach(pattern -> routeBuilder.addWebHook(clazz, pattern, hook)); + .forEach(pattern -> routeBuilder.addWebHook(clazz, pattern)); } } diff --git a/src/main/java/com/blade/server/netty/RouteMethodHandler.java b/src/main/java/com/blade/server/netty/RouteMethodHandler.java index 552a40614..6ae914871 100644 --- a/src/main/java/com/blade/server/netty/RouteMethodHandler.java +++ b/src/main/java/com/blade/server/netty/RouteMethodHandler.java @@ -39,7 +39,6 @@ import java.util.List; import java.util.Map; -import static com.blade.kit.BladeKit.log500; import static com.blade.server.netty.HttpConst.CONTENT_LENGTH; import static com.blade.server.netty.HttpConst.KEEP_ALIVE; import static io.netty.handler.codec.http.HttpHeaderNames.TRANSFER_ENCODING; @@ -225,7 +224,7 @@ private void routeHandle(RouteContext context) { if (null == target) { Class clazz = context.routeAction().getDeclaringClass(); target = WebContext.blade().getBean(clazz); - context.route().setTarget(target); +// context.route().setTarget(target); } if (context.targetType() == RouteHandler.class) { RouteHandler routeHandler = (RouteHandler) target; @@ -240,7 +239,10 @@ 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 isRestful = (null != JSON) || (null != path && path.restful()); + boolean isSingleton = path.singleton(); + + target = isSingleton ? target : WebContext.blade().ioc().createBean(target.getClass()); // if request is restful and not InternetExplorer userAgent if (isRestful) { @@ -291,7 +293,7 @@ private void routeHandle(RouteContext context) { */ private boolean invokeHook(RouteContext context, Route hookRoute) throws Exception { Method hookMethod = hookRoute.getAction(); - Object target = hookRoute.getTarget(); + Object target = WebContext.blade().ioc().getBean(hookRoute.getTargetType()); if (null == target) { Class clazz = hookRoute.getAction().getDeclaringClass(); target = WebContext.blade().ioc().getBean(clazz); @@ -335,7 +337,7 @@ private boolean invokeMiddleware(List middleware, return true; } for (Route route : middleware) { - WebHook webHook = (WebHook) route.getTarget(); + WebHook webHook = (WebHook) WebContext.blade().ioc().getBean(route.getTargetType()); boolean flag = webHook.before(context); if (!flag) return false; } diff --git a/src/test/java/com/blade/ioc/BeanDefineTest.java b/src/test/java/com/blade/ioc/BeanDefineTest.java index 286358206..5c03fe79f 100644 --- a/src/test/java/com/blade/ioc/BeanDefineTest.java +++ b/src/test/java/com/blade/ioc/BeanDefineTest.java @@ -21,15 +21,15 @@ public void testBeanDefine() { Object bean = beanDefine.getBean(); assertNotNull(bean); - assertEquals(true, beanDefine.isPrototype()); + assertEquals(true, beanDefine.isSingleton()); - beanDefine.setPrototype(true); + beanDefine.setSingleton(true); beanDefine.setType(BladeBeanDefineType.class); beanDefine.setBean(new BladeBeanDefineType()); assertEquals(BladeBeanDefineType.class, type); assertNotNull(bean); - assertEquals(true, beanDefine.isPrototype()); + assertEquals(true, beanDefine.isSingleton()); } @@ -40,7 +40,7 @@ public void testBeanDefine2() { beanDefine = new BeanDefine(new BladeBeanDefineType(), BladeBeanDefineType.class, true); assertEquals(BladeBeanDefineType.class, beanDefine.getType()); - assertEquals(true, beanDefine.isPrototype()); + assertEquals(true, beanDefine.isSingleton()); } } diff --git a/src/test/java/com/blade/mvc/route/RouteBuilderTest.java b/src/test/java/com/blade/mvc/route/RouteBuilderTest.java index 19144a899..f549811c3 100644 --- a/src/test/java/com/blade/mvc/route/RouteBuilderTest.java +++ b/src/test/java/com/blade/mvc/route/RouteBuilderTest.java @@ -18,7 +18,7 @@ public void testCreateRouteBuilder() throws Exception { RouteMatcher routeMatcher = new RouteMatcher(); RouteBuilder routeBuilder = new RouteBuilder(routeMatcher); routeBuilder.addRouter(DemoController.class, new DemoController()); - routeBuilder.addWebHook(WebHook.class, "/*", (WebHook) signature -> true); + routeBuilder.addWebHook(WebHook.class, "/*"); routeMatcher.register(); diff --git a/src/test/java/netty_hello/DemoController.java b/src/test/java/netty_hello/DemoController.java index 2cc9f4c33..b8dc09dac 100644 --- a/src/test/java/netty_hello/DemoController.java +++ b/src/test/java/netty_hello/DemoController.java @@ -1,5 +1,6 @@ package netty_hello; +import com.blade.ioc.annotation.Inject; import com.blade.mvc.annotation.*; import com.blade.mvc.http.Request; import com.blade.mvc.http.Response; @@ -17,12 +18,16 @@ * @author biezhi * @date 2018/4/18 */ -@Path +@Path(singleton = false) public class DemoController { + @Inject(singleton = false) + private UserService userService; + @GetRoute("p") public void p(@Param String p1) { System.out.println(p1); + userService.sayHello(); } @Route("hi/:a/:b/:c") From 503330d75b292b95960478d2de68bd780084ff31 Mon Sep 17 00:00:00 2001 From: biezhi Date: Wed, 21 Nov 2018 16:52:57 +0800 Subject: [PATCH 10/21] :sparkles: resolve #238 --- src/main/java/com/blade/ioc/Injector.java | 2 + src/main/java/com/blade/ioc/SimpleIoc.java | 2 +- .../java/com/blade/ioc/annotation/Inject.java | 2 +- .../java/com/blade/ioc/bean/BeanDefine.java | 10 ++--- .../com/blade/ioc/bean/FieldInjector.java | 17 ++++++++ .../com/blade/ioc/bean/ValueInjector.java | 39 +++++++++++-------- src/main/java/com/blade/kit/IocKit.java | 28 ++++++++++--- src/main/java/com/blade/mvc/RouteContext.java | 11 +++++- .../com/blade/server/netty/NettyServer.java | 2 +- 9 files changed, 82 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/blade/ioc/Injector.java b/src/main/java/com/blade/ioc/Injector.java index d05154f51..8378f4c7b 100644 --- a/src/main/java/com/blade/ioc/Injector.java +++ b/src/main/java/com/blade/ioc/Injector.java @@ -15,4 +15,6 @@ public interface Injector { */ void injection(Object bean); + void injection(Object bean, Object value); + } \ No newline at end of file diff --git a/src/main/java/com/blade/ioc/SimpleIoc.java b/src/main/java/com/blade/ioc/SimpleIoc.java index bb2215932..7fee7d5ee 100644 --- a/src/main/java/com/blade/ioc/SimpleIoc.java +++ b/src/main/java/com/blade/ioc/SimpleIoc.java @@ -74,7 +74,7 @@ public T addBean(Class type) { @Override public Object createBean(Class type) { BeanDefine beanDefine = createBeanDefine(type, true); - IocKit.injection(this, Objects.requireNonNull(beanDefine)); + IocKit.initInjection(this, Objects.requireNonNull(beanDefine)); IocKit.injectionValue(WebContext.blade().environment(), beanDefine); return beanDefine.getBean(); } diff --git a/src/main/java/com/blade/ioc/annotation/Inject.java b/src/main/java/com/blade/ioc/annotation/Inject.java index 052c501f3..a23c2ae90 100644 --- a/src/main/java/com/blade/ioc/annotation/Inject.java +++ b/src/main/java/com/blade/ioc/annotation/Inject.java @@ -6,7 +6,7 @@ import java.lang.annotation.Target; /** - * Automatic injection + * Automatic initInjection * * @author biezhi * @since 1.5 diff --git a/src/main/java/com/blade/ioc/bean/BeanDefine.java b/src/main/java/com/blade/ioc/bean/BeanDefine.java index 76ec7ada4..ae384b762 100644 --- a/src/main/java/com/blade/ioc/bean/BeanDefine.java +++ b/src/main/java/com/blade/ioc/bean/BeanDefine.java @@ -11,7 +11,7 @@ public class BeanDefine { private Object bean; private Class type; private boolean isSingleton; - private boolean hasPrototypeField; + private boolean fieldHasPrototype; public BeanDefine(Object bean) { this(bean, bean.getClass()); @@ -53,11 +53,11 @@ public void setSingleton(boolean isSingleton) { this.isSingleton = isSingleton; } - public boolean isHasPrototypeField() { - return hasPrototypeField; + public boolean isFieldHasPrototype() { + return fieldHasPrototype; } - public void setHasPrototypeField(boolean hasPrototypeField) { - this.hasPrototypeField = hasPrototypeField; + public void setFieldHasPrototype(boolean fieldHasPrototype) { + this.fieldHasPrototype = fieldHasPrototype; } } \ No newline at end of file diff --git a/src/main/java/com/blade/ioc/bean/FieldInjector.java b/src/main/java/com/blade/ioc/bean/FieldInjector.java index ecbc3415b..351a80fea 100644 --- a/src/main/java/com/blade/ioc/bean/FieldInjector.java +++ b/src/main/java/com/blade/ioc/bean/FieldInjector.java @@ -22,6 +22,10 @@ public FieldInjector(Ioc ioc, Field field) { this.field = field; } + public Class getType() { + return field.getType(); + } + public boolean isSingleton() { return IocKit.isSingleton(field.getType()); } @@ -34,6 +38,15 @@ public void injection(Object bean) { if (value == null) { throw new IllegalStateException("Can't inject bean: " + fieldType.getName() + " for field: " + field); } + injection(bean, value); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void injection(Object bean, Object value) { + try { field.setAccessible(true); field.set(bean, value); } catch (Exception e) { @@ -41,4 +54,8 @@ public void injection(Object bean) { } } + public boolean hasInjectFields() { + return field.getType().getDeclaredFields().length > 0; + } + } \ No newline at end of file diff --git a/src/main/java/com/blade/ioc/bean/ValueInjector.java b/src/main/java/com/blade/ioc/bean/ValueInjector.java index 3ce7bf563..826ad421b 100644 --- a/src/main/java/com/blade/ioc/bean/ValueInjector.java +++ b/src/main/java/com/blade/ioc/bean/ValueInjector.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import java.util.*; + /** * Config annotation can be injected * @@ -14,13 +15,13 @@ @Slf4j public class ValueInjector implements Injector { private Environment environment; - private Field target; - private String key; + private Field target; + private String key; public ValueInjector(Environment environment, Field target, String key) { this.environment = environment; - this.target = target; - this.key = key; + this.target = target; + this.key = key; } @Override @@ -31,40 +32,46 @@ public void injection(Object bean) { target.setAccessible(true); Optional value = environment.get(key); if (!value.isPresent()) { - log.warn("config is absent,so can't be injected:target is {}",bean.getClass().getName()); + log.warn("config is absent,so can't be injected:target is {}", bean.getClass().getName()); return; } if (value.get().isEmpty()) { - log.warn("config is empty,so can't be injected:target is {}",bean.getClass().getName()); + log.warn("config is empty,so can't be injected:target is {}", bean.getClass().getName()); return; } //target field type is String if (clazz.isAssignableFrom(String.class)) { - target.set(bean, value.isPresent()? value.get() : ""); + target.set(bean, value.isPresent() ? value.get() : ""); return; } //List and Map support,just support String element - String split = environment.get("value.split",","); - String mapSplit = environment.get("value.map.split",":"); + String split = environment.get("value.split", ","); + String mapSplit = environment.get("value.map.split", ":"); if (clazz.isAssignableFrom(List.class)) { - target.set(bean,Arrays.asList(value.get().split(split))); + target.set(bean, Arrays.asList(value.get().split(split))); return; } - Map map = new HashMap(16); + Map map = new HashMap(16); if (clazz.isAssignableFrom(Map.class)) { Arrays.stream(value.get().split(split)) .filter(d -> d.indexOf(mapSplit) != -1) .map(d -> d.split(mapSplit)) - .forEach(keyValue -> map.put(keyValue[0],keyValue[1])); - target.set(bean,map); + .forEach(keyValue -> map.put(keyValue[0], keyValue[1])); + target.set(bean, map); return; } - }else { - log.warn("key is empty,so can't be injected:target is {}",bean.getClass().getName()); + } else { + log.warn("key is empty,so can't be injected:target is {}", bean.getClass().getName()); } } catch (IllegalAccessException e) { - log.error("inject config error! key is {},bean is {}",key,bean.getClass().getSimpleName(),e); + log.error("inject config error! key is {},bean is {}", key, bean.getClass().getSimpleName(), e); } } + + @Override + public void injection(Object bean, Object value) { + // TODO + } + } diff --git a/src/main/java/com/blade/kit/IocKit.java b/src/main/java/com/blade/kit/IocKit.java index f6eb0d2bb..c3f546a27 100644 --- a/src/main/java/com/blade/kit/IocKit.java +++ b/src/main/java/com/blade/kit/IocKit.java @@ -25,6 +25,7 @@ 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; @@ -51,7 +52,7 @@ public class IocKit { * @return return FieldInjector */ private static List getInjectFields(Ioc ioc, ClassDefine classDefine) { - List injectors = new ArrayList<>(8); + List injectors = new ArrayList<>(); for (Field field : classDefine.getDeclaredFields()) { if (null != field.getAnnotation(InjectWith.class) || null != field.getAnnotation(Inject.class)) { injectors.add(new FieldInjector(ioc, field)); @@ -92,16 +93,33 @@ public static void injection(Ioc ioc, BeanDefine beanDefine) { ClassDefine classDefine = ClassDefine.create(beanDefine.getType()); List fieldInjectors = getInjectFields(ioc, classDefine); + Object bean = beanDefine.getBean(); + fieldInjectors.forEach(fieldInjector -> { + Object fieldInstance = ReflectKit.newInstance(fieldInjector.getType()); + if (fieldInjector.hasInjectFields()) { + injection(ioc, new BeanDefine(fieldInstance)); + } + fieldInjector.injection(bean, fieldInstance); + }); + } + + public static void initInjection(Ioc ioc, BeanDefine beanDefine) { + ClassDefine classDefine = ClassDefine.create(beanDefine.getType()); + List fieldInjectors = getInjectFields(ioc, classDefine); + Object bean = beanDefine.getBean(); AtomicBoolean hasPrototypeField = new AtomicBoolean(false); - fieldInjectors.stream().filter(FieldInjector::isSingleton).forEach(fieldInjector -> { - fieldInjector.injection(bean); - hasPrototypeField.set(true); + fieldInjectors.forEach(fieldInjector -> { + if (fieldInjector.isSingleton()) { + fieldInjector.injection(bean); + } else { + hasPrototypeField.set(true); + } }); - beanDefine.setHasPrototypeField(hasPrototypeField.get()); + beanDefine.setFieldHasPrototype(hasPrototypeField.get()); } public static void injectionValue(Environment environment, BeanDefine beanDefine) { diff --git a/src/main/java/com/blade/mvc/RouteContext.java b/src/main/java/com/blade/mvc/RouteContext.java index 505d9c23b..857bea275 100644 --- a/src/main/java/com/blade/mvc/RouteContext.java +++ b/src/main/java/com/blade/mvc/RouteContext.java @@ -15,6 +15,7 @@ */ package com.blade.mvc; +import com.blade.ioc.bean.BeanDefine; import com.blade.kit.IocKit; import com.blade.mvc.http.Body; import com.blade.mvc.http.Request; @@ -527,8 +528,14 @@ public void initRoute(Route route) { boolean singleton = IocKit.isSingleton(route.getTargetType()); if (singleton) { - Object target = WebContext.blade().ioc().getBean(route.getTargetType()); - this.route.setTarget(target); + 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); diff --git a/src/main/java/com/blade/server/netty/NettyServer.java b/src/main/java/com/blade/server/netty/NettyServer.java index 682e4b87e..02cd77110 100644 --- a/src/main/java/com/blade/server/netty/NettyServer.java +++ b/src/main/java/com/blade/server/netty/NettyServer.java @@ -167,7 +167,7 @@ private void initIoc() { if (BladeKit.isNotEmpty(beanDefines)) { beanDefines.forEach(b -> { - IocKit.injection(ioc, b); + IocKit.initInjection(ioc, b); IocKit.injectionValue(environment, b); List cronExpressions = BladeKit.getTasks(b.getType()); if (null != cronExpressions) { From 7abecc2ff19c97823dde679e5e0d89581bd21832 Mon Sep 17 00:00:00 2001 From: biezhi Date: Wed, 21 Nov 2018 17:00:48 +0800 Subject: [PATCH 11/21] :sparkles: resolve #238 --- src/test/java/netty_hello/BService.java | 16 +++++++++++++ src/test/java/netty_hello/CService.java | 16 +++++++++++++ src/test/java/netty_hello/DemoController.java | 4 ++-- src/test/java/netty_hello/UserService.java | 24 +++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 src/test/java/netty_hello/BService.java create mode 100644 src/test/java/netty_hello/CService.java create mode 100644 src/test/java/netty_hello/UserService.java diff --git a/src/test/java/netty_hello/BService.java b/src/test/java/netty_hello/BService.java new file mode 100644 index 000000000..106d7e676 --- /dev/null +++ b/src/test/java/netty_hello/BService.java @@ -0,0 +1,16 @@ +package netty_hello; + +import com.blade.ioc.annotation.Bean; + +/** + * @author biezhi + * @date 2018-11-21 + */ +@Bean(singleton = false) +public class BService { + + public void sayHello(){ + System.out.println("B...Hello"); + } + +} diff --git a/src/test/java/netty_hello/CService.java b/src/test/java/netty_hello/CService.java new file mode 100644 index 000000000..c0aa694bb --- /dev/null +++ b/src/test/java/netty_hello/CService.java @@ -0,0 +1,16 @@ +package netty_hello; + +import com.blade.ioc.annotation.Bean; + +/** + * @author biezhi + * @date 2018-11-21 + */ +@Bean +public class CService { + + public void sayHello(){ + System.out.println("c...Hello"); + } + +} diff --git a/src/test/java/netty_hello/DemoController.java b/src/test/java/netty_hello/DemoController.java index b8dc09dac..030d76ce6 100644 --- a/src/test/java/netty_hello/DemoController.java +++ b/src/test/java/netty_hello/DemoController.java @@ -18,10 +18,10 @@ * @author biezhi * @date 2018/4/18 */ -@Path(singleton = false) +@Path public class DemoController { - @Inject(singleton = false) + @Inject private UserService userService; @GetRoute("p") diff --git a/src/test/java/netty_hello/UserService.java b/src/test/java/netty_hello/UserService.java new file mode 100644 index 000000000..7e16ab0d6 --- /dev/null +++ b/src/test/java/netty_hello/UserService.java @@ -0,0 +1,24 @@ +package netty_hello; + +import com.blade.ioc.annotation.Bean; +import com.blade.ioc.annotation.Inject; + +/** + * @author biezhi + * @date 2018-11-21 + */ +@Bean(singleton = false) +public class UserService { + + @Inject + private BService bService; + + @Inject + private CService cService; + + public void sayHello(){ + bService.sayHello(); + cService.sayHello(); + } + +} From 60e844a5b7e32205aafcd33404f4af041f8b63ff Mon Sep 17 00:00:00 2001 From: psh686868 Date: Mon, 26 Nov 2018 11:42:12 +0800 Subject: [PATCH 12/21] bugfix: update corsMiddleware allowOrigin => allowHead and improve enableCors method --- src/main/java/com/blade/Blade.java | 6 +-- .../security/web/cors/CorsMiddleware.java | 39 ++++++++++++------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/blade/Blade.java b/src/main/java/com/blade/Blade.java index 5fd08add6..14ba5495a 100644 --- a/src/main/java/com/blade/Blade.java +++ b/src/main/java/com/blade/Blade.java @@ -535,17 +535,17 @@ public Class bootClass() { * @return blade */ public Blade enableCors(boolean enableCors) { - this.enableCors(new CorsConfiger(), enableCors); + this.enableCors(enableCors, new CorsConfiger()); return this; } /** * Set whether to config cors - * @param corsConfig config cors * @param enableCors enable cors + * @param corsConfig config cors * @return blade */ - public Blade enableCors(CorsConfiger corsConfig, boolean enableCors) { + public Blade enableCors(boolean enableCors, CorsConfiger corsConfig) { this.environment.set(ENV_KEY_CORS_ENABLE, enableCors); if (enableCors) { this.use(new CorsMiddleware(corsConfig)); 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 75cc3a50e..a981c469e 100644 --- a/src/main/java/com/blade/security/web/cors/CorsMiddleware.java +++ b/src/main/java/com/blade/security/web/cors/CorsMiddleware.java @@ -2,9 +2,7 @@ import com.blade.mvc.RouteContext; import com.blade.mvc.hook.WebHook; -import com.blade.mvc.http.Request; import io.netty.handler.codec.http.HttpHeaderNames; -import io.netty.util.internal.StringUtil; import java.util.StringJoiner; import java.util.stream.Collector; import lombok.extern.slf4j.Slf4j; @@ -31,7 +29,7 @@ public CorsMiddleware(CorsConfiger corsConfiger) { public boolean before(RouteContext context) { this.allowCredentials(context) .allowMethods(context) - .allowOrigin(context) + .allowHeads(context) .setMaxAge(context) .allowCredentials(context); if ("OPTIONS".equals(context.method())) { @@ -40,20 +38,30 @@ public boolean before(RouteContext context) { return true; } - private CorsMiddleware allowOrigin(RouteContext context) { - Request request = context.request(); - String originUrl = request.header(HttpHeaderNames.ORIGIN.toString()); - if (StringUtil.isNullOrEmpty(originUrl)) { - originUrl = CorsConfiger.ALL; + private CorsMiddleware allowHeads(RouteContext context) { + boolean isDefaultAllowHeads = corsConfig == null || corsConfig.getAllowedHeaders() == null + || corsConfig.getAllowedHeaders().size() == 0; + + if (isDefaultAllowHeads) { + context.response().header("Access-Control-Allow-Headers", CorsConfiger.ALL); + return this; } - context.header("Access-Control-Allow-Headers", originUrl); + + String heads = corsConfig.getAllowedHeaders().stream().collect(Collector.of( + () -> new StringJoiner(", "), + (j, head) -> j.add(head.toUpperCase()), + StringJoiner::merge, + StringJoiner::toString + )); + context.response().header("Access-Control-Allow-Headers", heads); return this; } private CorsMiddleware allowMethods(RouteContext context) { - if (corsConfig == null || corsConfig.getAllowedMethods() == null - || corsConfig.getAllowedMethods().size() == 0) { + boolean isDefaultAllowMethods = corsConfig == null || corsConfig.getAllowedMethods() == null + || corsConfig.getAllowedMethods().size() == 0; + if (isDefaultAllowMethods) { context.header("Access-Control-Allow-Methods", CorsConfiger.DEFAULT_ALLOWED_METHODS); return this; @@ -65,12 +73,15 @@ private CorsMiddleware allowMethods(RouteContext context) { StringJoiner::merge, StringJoiner::toString )); + context.response().header("Access-Control-Allow-Methods", methods); return this; } private CorsMiddleware allowCredentials(RouteContext context) { - if (corsConfig == null || corsConfig.getAllowCredentials() == null) { + boolean isDefaultAllowCredentials = corsConfig == null || corsConfig.getAllowCredentials() == null; + + if (isDefaultAllowCredentials) { context.header("Access-Control-Allow-Credentials", CorsConfiger.DEFAULT_ALLOW_CREDENTIALS); return this; @@ -81,8 +92,8 @@ private CorsMiddleware allowCredentials(RouteContext context) { } private CorsMiddleware setMaxAge(RouteContext context) { - - if (corsConfig == null || corsConfig.getMaxAge() == null) { + boolean isDefaultMaxAge = corsConfig == null || corsConfig.getMaxAge() == null; + if (isDefaultMaxAge) { context.response().header("Access-Control-Max-Age", CorsConfiger.DEFAULT_MAX_AGE.toString()); return this; From af20f5f711cfac46d4b5bf5c919bd0a28fc586ab Mon Sep 17 00:00:00 2001 From: psh686868 Date: Mon, 26 Nov 2018 11:53:53 +0800 Subject: [PATCH 13/21] update: modify access-control-allow-origin head Name --- src/main/java/com/blade/security/web/cors/CorsMiddleware.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a981c469e..a859a8dd5 100644 --- a/src/main/java/com/blade/security/web/cors/CorsMiddleware.java +++ b/src/main/java/com/blade/security/web/cors/CorsMiddleware.java @@ -98,7 +98,7 @@ private CorsMiddleware setMaxAge(RouteContext context) { CorsConfiger.DEFAULT_MAX_AGE.toString()); return this; } - context.header(HttpHeaderNames.ACCESS_CONTROL_MAX_AGE.toString(), corsConfig.getMaxAge().toString()); + context.header("Access-Control-Max-Age", corsConfig.getMaxAge().toString()); return this; } From 3888bde9f3e1503b75538e708d34b5180563b011 Mon Sep 17 00:00:00 2001 From: biezhi Date: Mon, 26 Nov 2018 11:57:40 +0800 Subject: [PATCH 14/21] :bug: fixed isAjax incomplete judgment --- src/main/java/com/blade/mvc/http/Request.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/blade/mvc/http/Request.java b/src/main/java/com/blade/mvc/http/Request.java index 5c61ce63a..5a63ed83e 100644 --- a/src/main/java/com/blade/mvc/http/Request.java +++ b/src/main/java/com/blade/mvc/http/Request.java @@ -318,7 +318,7 @@ default String contentType() { * @return Return current request is a AJAX request */ default boolean isAjax() { - return "XMLHttpRequest".equals(header("x-requested-with")); + return "XMLHttpRequest".equals(header("X-Requested-With")) || "XMLHttpRequest".equals(header("x-requested-with")); } /** From c9833d6069aeeb7e2c302bc503a5881c4256e056 Mon Sep 17 00:00:00 2001 From: biezhi Date: Mon, 26 Nov 2018 11:58:29 +0800 Subject: [PATCH 15/21] :bug: fixed reading http body incomplete --- .../java/com/blade/mvc/http/HttpRequest.java | 62 +++++++++++-------- .../server/netty/MergeRequestHandler.java | 6 +- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/blade/mvc/http/HttpRequest.java b/src/main/java/com/blade/mvc/http/HttpRequest.java index c41ff2217..6f4ce8b0d 100644 --- a/src/main/java/com/blade/mvc/http/HttpRequest.java +++ b/src/main/java/com/blade/mvc/http/HttpRequest.java @@ -27,6 +27,8 @@ import com.blade.server.netty.HttpConst; import com.blade.server.netty.HttpServerHandler; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.CompositeByteBuf; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.cookie.ServerCookieDecoder; @@ -69,11 +71,11 @@ public class HttpRequest implements Request { } private ByteBuf body = EMPTY_BUF; - private String remoteAddress; - private String uri; - private String url; - private String protocol; - private String method; + private String remoteAddress; + private String uri; + private String url; + private String protocol; + private String method; private boolean keepAlive; private Session session; @@ -87,16 +89,16 @@ public class HttpRequest implements Request { private HttpHeaders httpHeaders; private io.netty.handler.codec.http.HttpRequest nettyRequest; - private HttpPostRequestDecoder decoder; + private HttpPostRequestDecoder decoder; private Queue contents = new LinkedList<>(); - private Map headers = null; - private Map attributes = null; - private Map pathParams = null; + private Map headers = null; + private Map attributes = null; + private Map pathParams = null; private Map> parameters = new HashMap<>(8); - private Map cookies = new HashMap<>(8); - private Map fileItems = new HashMap<>(8); + private Map cookies = new HashMap<>(8); + private Map fileItems = new HashMap<>(8); public HttpRequest(Request request) { this.pathParams = request.pathParams(); @@ -165,18 +167,20 @@ public String queryString() { @Override public Map> parameters() { - if (!initQueryParam) { - initQueryParam = true; - if (!url.contains("?")) { - return this.parameters; - } + if (initQueryParam) { + return this.parameters; + } - var parameters = - new QueryStringDecoder(url, CharsetUtil.UTF_8).parameters(); + initQueryParam = true; + if (!url.contains("?")) { + return this.parameters; + } - if (null != parameters) { - this.parameters.putAll(parameters); - } + var parameters = + new QueryStringDecoder(url, CharsetUtil.UTF_8).parameters(); + + if (null != parameters) { + this.parameters.putAll(parameters); } return this.parameters; } @@ -346,14 +350,21 @@ public void init(String remoteAddress) { try { HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(factory, nettyRequest); this.isMultipart = decoder.isMultipart(); + + List byteBufs = new ArrayList<>(this.contents.size()); + for (HttpContent content : this.contents) { - if (!isMultipart && content instanceof LastHttpContent) { - this.body = content.duplicate().content().copy(); + if (!isMultipart) { + byteBufs.add(content.content().copy()); } + decoder.offer(content); this.readHttpDataChunkByChunk(decoder); content.release(); } + if (!byteBufs.isEmpty()) { + this.body = Unpooled.copiedBuffer(byteBufs.stream().toArray(ByteBuf[]::new)); + } } catch (Exception e) { throw new HttpParseException("build decoder fail", e); } @@ -405,7 +416,7 @@ private void writeHttpData(InterfaceHttpData data) { } private void parseAttribute(Attribute attribute) throws IOException { - var name = attribute.getName(); + var name = attribute.getName(); var value = attribute.getValue(); List values; @@ -465,7 +476,4 @@ private void parseCookie(io.netty.handler.codec.http.cookie.Cookie nettyCookie) this.cookies.put(cookie.name(), cookie); } - public HttpPostRequestDecoder getDecoder() { - return decoder; - } } \ No newline at end of file diff --git a/src/main/java/com/blade/server/netty/MergeRequestHandler.java b/src/main/java/com/blade/server/netty/MergeRequestHandler.java index ddb61ab06..5ffdb37aa 100644 --- a/src/main/java/com/blade/server/netty/MergeRequestHandler.java +++ b/src/main/java/com/blade/server/netty/MergeRequestHandler.java @@ -47,7 +47,11 @@ protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) { httpRequest.appendContent((HttpContent) msg); } if (msg instanceof LastHttpContent) { - ctx.fireChannelRead(httpRequest); + if (null != httpRequest) { + ctx.fireChannelRead(httpRequest); + } else { + ctx.fireChannelRead(msg); + } } } From 6af9a90f58c05c25c531a533ff83be989534064a Mon Sep 17 00:00:00 2001 From: psh686868 Date: Mon, 26 Nov 2018 11:59:08 +0800 Subject: [PATCH 16/21] update: delete corsMiddleware useless import --- src/main/java/com/blade/security/web/cors/CorsMiddleware.java | 1 - 1 file changed, 1 deletion(-) 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 a859a8dd5..8c0392fdd 100644 --- a/src/main/java/com/blade/security/web/cors/CorsMiddleware.java +++ b/src/main/java/com/blade/security/web/cors/CorsMiddleware.java @@ -2,7 +2,6 @@ import com.blade.mvc.RouteContext; import com.blade.mvc.hook.WebHook; -import io.netty.handler.codec.http.HttpHeaderNames; import java.util.StringJoiner; import java.util.stream.Collector; import lombok.extern.slf4j.Slf4j; From c75de9960ec905aa9f01c97e30cd20063776a37d Mon Sep 17 00:00:00 2001 From: biezhi Date: Mon, 26 Nov 2018 12:00:04 +0800 Subject: [PATCH 17/21] :bug: fixed reading http body incomplete --- src/main/java/com/blade/server/netty/MergeRequestHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/blade/server/netty/MergeRequestHandler.java b/src/main/java/com/blade/server/netty/MergeRequestHandler.java index 5ffdb37aa..0affb55e7 100644 --- a/src/main/java/com/blade/server/netty/MergeRequestHandler.java +++ b/src/main/java/com/blade/server/netty/MergeRequestHandler.java @@ -43,7 +43,7 @@ protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) { httpRequest.setNettyRequest((io.netty.handler.codec.http.HttpRequest) msg); return; } - if (msg instanceof HttpContent) { + if (null != httpRequest && msg instanceof HttpContent) { httpRequest.appendContent((HttpContent) msg); } if (msg instanceof LastHttpContent) { From 699f0cecaa027440832a3ca8fae7d2d4a4f5689e Mon Sep 17 00:00:00 2001 From: psh686868 Date: Mon, 26 Nov 2018 13:47:30 +0800 Subject: [PATCH 18/21] update: remove head values toUpperCase --- src/main/java/com/blade/security/web/cors/CorsMiddleware.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8c0392fdd..867e8155b 100644 --- a/src/main/java/com/blade/security/web/cors/CorsMiddleware.java +++ b/src/main/java/com/blade/security/web/cors/CorsMiddleware.java @@ -48,7 +48,7 @@ private CorsMiddleware allowHeads(RouteContext context) { String heads = corsConfig.getAllowedHeaders().stream().collect(Collector.of( () -> new StringJoiner(", "), - (j, head) -> j.add(head.toUpperCase()), + (j, head) -> j.add(head), StringJoiner::merge, StringJoiner::toString )); From 4654784521bf0e83e41a45ad51c3688d6d87361b Mon Sep 17 00:00:00 2001 From: psh686868 Date: Mon, 26 Nov 2018 13:52:28 +0800 Subject: [PATCH 19/21] update: trim head values --- src/main/java/com/blade/security/web/cors/CorsMiddleware.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 867e8155b..aea32749b 100644 --- a/src/main/java/com/blade/security/web/cors/CorsMiddleware.java +++ b/src/main/java/com/blade/security/web/cors/CorsMiddleware.java @@ -47,7 +47,7 @@ private CorsMiddleware allowHeads(RouteContext context) { } String heads = corsConfig.getAllowedHeaders().stream().collect(Collector.of( - () -> new StringJoiner(", "), + () -> new StringJoiner(","), (j, head) -> j.add(head), StringJoiner::merge, StringJoiner::toString From d3a2da3e760ece87d24f5f409801f689e57c2bd2 Mon Sep 17 00:00:00 2001 From: biezhi Date: Mon, 26 Nov 2018 16:55:04 +0800 Subject: [PATCH 20/21] :bug: fixed #295 --- pom.xml | 2 +- src/main/java/com/blade/Blade.java | 2 +- .../com/blade/ioc/bean/ValueInjector.java | 38 ++++++++++++------- src/test/java/com/blade/model/AppInfo.java | 10 ++--- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/pom.xml b/pom.xml index 2e35719bd..59a17d96c 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bladejava blade-mvc - 2.0.12.ALPHA + 2.0.13-SNAPSHOT jar blade diff --git a/src/main/java/com/blade/Blade.java b/src/main/java/com/blade/Blade.java index ee9f8a2c3..63d4b0eeb 100644 --- a/src/main/java/com/blade/Blade.java +++ b/src/main/java/com/blade/Blade.java @@ -849,11 +849,11 @@ public Blade start() { */ public Blade start(Class mainCls, String... args) { try { - Assert.packageNotEmpty(mainCls,"your main class is empty of package."); this.loadConfig(args); this.bootClass = mainCls; eventManager.fireEvent(EventType.SERVER_STARTING, new Event().attribute("blade", this)); + Thread thread = new Thread(() -> { try { server.start(Blade.this); diff --git a/src/main/java/com/blade/ioc/bean/ValueInjector.java b/src/main/java/com/blade/ioc/bean/ValueInjector.java index 826ad421b..584ce416c 100644 --- a/src/main/java/com/blade/ioc/bean/ValueInjector.java +++ b/src/main/java/com/blade/ioc/bean/ValueInjector.java @@ -2,6 +2,8 @@ import com.blade.Environment; import com.blade.ioc.Injector; +import com.blade.kit.ReflectKit; +import com.blade.kit.StringKit; import lombok.extern.slf4j.Slf4j; import java.lang.reflect.Field; @@ -15,8 +17,8 @@ @Slf4j public class ValueInjector implements Injector { private Environment environment; - private Field target; - private String key; + private Field target; + private String key; public ValueInjector(Environment environment, Field target, String key) { this.environment = environment; @@ -30,32 +32,40 @@ public void injection(Object bean) { if (!key.isEmpty()) { Class clazz = target.getType(); target.setAccessible(true); - Optional value = environment.get(key); - if (!value.isPresent()) { + Optional fieldValue = environment.get(key); + if (!fieldValue.isPresent()) { log.warn("config is absent,so can't be injected:target is {}", bean.getClass().getName()); return; } - if (value.get().isEmpty()) { + + if (fieldValue.get().isEmpty()) { log.warn("config is empty,so can't be injected:target is {}", bean.getClass().getName()); return; } - //target field type is String - if (clazz.isAssignableFrom(String.class)) { - target.set(bean, value.isPresent() ? value.get() : ""); - return; + + Object value = null; + + //target field type is Basic Type + if (ReflectKit.isBasicType(clazz)) { + if (fieldValue.isPresent() && StringKit.isNotBlank(fieldValue.get())) { + value = ReflectKit.convert(clazz, fieldValue.get()); + } + if (null != value) { + ReflectKit.setFieldValue(target, bean, value); + } } //List and Map support,just support String element - String split = environment.get("value.split", ","); + String split = environment.get("value.split", ","); String mapSplit = environment.get("value.map.split", ":"); if (clazz.isAssignableFrom(List.class)) { - target.set(bean, Arrays.asList(value.get().split(split))); + target.set(bean, Arrays.asList(fieldValue.get().split(split))); return; } - Map map = new HashMap(16); + Map map = new HashMap<>(16); if (clazz.isAssignableFrom(Map.class)) { - Arrays.stream(value.get().split(split)) - .filter(d -> d.indexOf(mapSplit) != -1) + Arrays.stream(fieldValue.get().split(split)) + .filter(d -> d.contains(mapSplit)) .map(d -> d.split(mapSplit)) .forEach(keyValue -> map.put(keyValue[0], keyValue[1])); target.set(bean, map); diff --git a/src/test/java/com/blade/model/AppInfo.java b/src/test/java/com/blade/model/AppInfo.java index a2c322a56..0d14e4952 100644 --- a/src/test/java/com/blade/model/AppInfo.java +++ b/src/test/java/com/blade/model/AppInfo.java @@ -10,10 +10,10 @@ @Value(name = "app") @Data public class AppInfo { - private String users; - private String maxMoney; - private String sex; - private String hits; + private int users; + private double maxMoney; + private boolean sex; + private Long hits; private String startDate; - + private int age; } From 130b89ab36f3fe62980811dee4d1e0d0c8e87302 Mon Sep 17 00:00:00 2001 From: biezhi Date: Mon, 26 Nov 2018 17:30:05 +0800 Subject: [PATCH 21/21] :bookmark: release 2.0.12.BETA --- README.md | 4 ++-- README_CN.md | 4 ++-- pom.xml | 2 +- src/main/java/com/blade/mvc/Const.java | 2 +- .../java/com/blade/mvc/http/HttpRequest.java | 16 +++++++--------- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index cf01e0737..af317602f 100644 --- a/README.md +++ b/README.md @@ -64,14 +64,14 @@ Run with `Maven`: com.bladejava blade-mvc - 2.0.12.ALPHA + 2.0.12.BETA ``` or `Gradle`: ```sh -compile 'com.bladejava:blade-mvc:2.0.12.ALPHA' +compile 'com.bladejava:blade-mvc:2.0.12.BETA' ``` Write the `main` method and the `Hello World`: diff --git a/README_CN.md b/README_CN.md index eeacac06d..a4a3997bc 100644 --- a/README_CN.md +++ b/README_CN.md @@ -61,7 +61,7 @@ com.bladejava blade-mvc - 2.0.12.ALPHA + 2.0.12.BETA ``` @@ -70,7 +70,7 @@ 或者 `Gradle`: ```sh -compile 'com.bladejava:blade-mvc:2.0.12.ALPHA' +compile 'com.bladejava:blade-mvc:2.0.12.BETA' ``` 编写 `main` 函数写一个 `Hello World`: diff --git a/pom.xml b/pom.xml index 59a17d96c..d528325f9 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bladejava blade-mvc - 2.0.13-SNAPSHOT + 2.0.12.BETA jar blade diff --git a/src/main/java/com/blade/mvc/Const.java b/src/main/java/com/blade/mvc/Const.java index 8f6417de0..27bb935f9 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.ALPHA"; + String VERSION = "2.0.12.BETA"; 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/http/HttpRequest.java b/src/main/java/com/blade/mvc/http/HttpRequest.java index 6f4ce8b0d..4a769454d 100644 --- a/src/main/java/com/blade/mvc/http/HttpRequest.java +++ b/src/main/java/com/blade/mvc/http/HttpRequest.java @@ -27,8 +27,6 @@ import com.blade.server.netty.HttpConst; import com.blade.server.netty.HttpServerHandler; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.CompositeByteBuf; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.cookie.ServerCookieDecoder; @@ -56,8 +54,8 @@ @NoArgsConstructor public class HttpRequest implements Request { - private static final HttpDataFactory factory = - new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // Disk if size exceed + private static final HttpDataFactory HTTP_DATA_FACTORY = + new DefaultHttpDataFactory(true); // Disk if size exceed private static final ByteBuf EMPTY_BUF = Unpooled.copiedBuffer("", CharsetUtil.UTF_8); @@ -348,22 +346,22 @@ public void init(String remoteAddress) { } try { - HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(factory, nettyRequest); + HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(HTTP_DATA_FACTORY, nettyRequest); this.isMultipart = decoder.isMultipart(); - List byteBufs = new ArrayList<>(this.contents.size()); + List byteBuffs = new ArrayList<>(this.contents.size()); for (HttpContent content : this.contents) { if (!isMultipart) { - byteBufs.add(content.content().copy()); + byteBuffs.add(content.content().copy()); } decoder.offer(content); this.readHttpDataChunkByChunk(decoder); content.release(); } - if (!byteBufs.isEmpty()) { - this.body = Unpooled.copiedBuffer(byteBufs.stream().toArray(ByteBuf[]::new)); + if (!byteBuffs.isEmpty()) { + this.body = Unpooled.copiedBuffer(byteBuffs.toArray(new ByteBuf[0])); } } catch (Exception e) { throw new HttpParseException("build decoder fail", e);