diff --git a/microsphere-spring-context/src/main/java/io/microsphere/spring/beans/BeanUtils.java b/microsphere-spring-context/src/main/java/io/microsphere/spring/beans/BeanUtils.java index 5279e464..88d51c6b 100644 --- a/microsphere-spring-context/src/main/java/io/microsphere/spring/beans/BeanUtils.java +++ b/microsphere-spring-context/src/main/java/io/microsphere/spring/beans/BeanUtils.java @@ -44,7 +44,6 @@ import static io.microsphere.spring.context.ApplicationContextUtils.getApplicationContextAwareProcessor; import static io.microsphere.util.ArrayUtils.isEmpty; import static io.microsphere.util.ClassLoaderUtils.resolveClass; -import static java.lang.String.format; import static java.util.Collections.emptyList; import static java.util.Collections.unmodifiableList; import static org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors; @@ -264,7 +263,6 @@ public static T getOptionalBean(ListableBeanFactory beanFactory, Class be * @param the bean type * @return the bean if available, or null * @throws BeansException in case of creation errors - * @since 1.0.0 */ public static T getBeanIfAvailable(BeanFactory beanFactory, String beanName, Class beanType) throws BeansException { if (isBeanPresent(beanFactory, beanName, beanType)) { @@ -272,7 +270,7 @@ public static T getBeanIfAvailable(BeanFactory beanFactory, String beanName, } if (logger.isTraceEnabled()) { - logger.trace(format("The bean[name : %s , type : %s] can't be found in Spring BeanFactory", beanName, beanType.getName())); + logger.trace("The bean[name : '{}' , type : {}] can't be found in Spring BeanFactory", beanName, beanType.getName()); } return null; } diff --git a/microsphere-spring-context/src/main/java/io/microsphere/spring/beans/factory/annotation/AnnotatedInjectionBeanPostProcessor.java b/microsphere-spring-context/src/main/java/io/microsphere/spring/beans/factory/annotation/AnnotatedInjectionBeanPostProcessor.java index 1c06798e..21234f94 100644 --- a/microsphere-spring-context/src/main/java/io/microsphere/spring/beans/factory/annotation/AnnotatedInjectionBeanPostProcessor.java +++ b/microsphere-spring-context/src/main/java/io/microsphere/spring/beans/factory/annotation/AnnotatedInjectionBeanPostProcessor.java @@ -70,9 +70,11 @@ import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.spring.beans.factory.BeanFactoryUtils.asConfigurableListableBeanFactory; import static io.microsphere.spring.core.annotation.AnnotationUtils.getAnnotationAttributes; +import static java.lang.Integer.getInteger; import static java.util.Collections.singleton; import static java.util.Collections.unmodifiableCollection; import static org.springframework.beans.BeanUtils.findPrimaryConstructor; +import static org.springframework.beans.factory.annotation.InjectionMetadata.needsRefresh; import static org.springframework.core.BridgeMethodResolver.findBridgedMethod; import static org.springframework.core.BridgeMethodResolver.isVisibilityBridgeMethodPair; import static org.springframework.util.Assert.notEmpty; @@ -110,7 +112,7 @@ public class AnnotatedInjectionBeanPostProcessor extends InstantiationAwareBeanP implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, InitializingBean, DisposableBean { - private final static int CACHE_SIZE = Integer.getInteger("microsphere.spring.injection.metadata.cache.size", 32); + private final static int CACHE_SIZE = getInteger("microsphere.spring.injection.metadata.cache.size", 32); private final Logger logger = getLogger(getClass()); @@ -419,10 +421,10 @@ private InjectionMetadata findInjectionMetadata(String beanName, Class clazz, String cacheKey = (hasLength(beanName) ? beanName : clazz.getName()); // Quick check on the concurrent map first, with minimal locking. AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); - if (InjectionMetadata.needsRefresh(metadata, clazz)) { + if (needsRefresh(metadata, clazz)) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(cacheKey); - if (InjectionMetadata.needsRefresh(metadata, clazz)) { + if (needsRefresh(metadata, clazz)) { if (metadata != null) { metadata.clear(pvs); } diff --git a/microsphere-spring-context/src/main/java/io/microsphere/spring/context/annotation/AnnotatedBeanDefinitionRegistryUtils.java b/microsphere-spring-context/src/main/java/io/microsphere/spring/context/annotation/AnnotatedBeanDefinitionRegistryUtils.java index e1811743..d80cca17 100644 --- a/microsphere-spring-context/src/main/java/io/microsphere/spring/context/annotation/AnnotatedBeanDefinitionRegistryUtils.java +++ b/microsphere-spring-context/src/main/java/io/microsphere/spring/context/annotation/AnnotatedBeanDefinitionRegistryUtils.java @@ -28,7 +28,6 @@ import static io.microsphere.util.ArrayUtils.EMPTY_CLASS_ARRAY; import static io.microsphere.util.ArrayUtils.isEmpty; import static io.microsphere.util.ArrayUtils.isNotEmpty; -import static java.lang.String.format; import static java.util.Arrays.asList; import static org.springframework.context.annotation.AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR; import static org.springframework.util.ClassUtils.resolveClassName; @@ -51,7 +50,6 @@ public abstract class AnnotatedBeanDefinitionRegistryUtils extends BaseUtils { * @param registry {@link BeanDefinitionRegistry} * @param annotatedClass the {@link Annotation annotated} {@link Class class} * @return if present, return true, or false - * @since 1.0.0 */ public static boolean isPresentBean(BeanDefinitionRegistry registry, Class annotatedClass) { @@ -70,8 +68,8 @@ public static boolean isPresentBean(BeanDefinitionRegistry registry, Class an present = nullSafeEquals(targetClass, annotatedClass); if (present) { if (logger.isTraceEnabled()) { - logger.trace(format("The annotatedClass[class : %s , bean name : %s] was present in registry[%s]", - className, beanName, registry)); + logger.trace("The annotatedClass[class : '{}' , bean name : '{}'] was present in registry : {}", + className, beanName, registry); } break; } @@ -170,7 +168,6 @@ public static int scanBasePackages(BeanDefinitionRegistry registry, String... ba * @see SingletonBeanRegistry * @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR * @see ConfigurationClassPostProcessor#processConfigBeanDefinitions - * @since 1.0.0 */ public static BeanNameGenerator resolveAnnotatedBeanNameGenerator(BeanDefinitionRegistry registry) { BeanNameGenerator beanNameGenerator = null; diff --git a/microsphere-spring-context/src/main/java/io/microsphere/spring/core/convert/support/ConversionServiceResolver.java b/microsphere-spring-context/src/main/java/io/microsphere/spring/core/convert/support/ConversionServiceResolver.java index 42d6665c..c658065c 100644 --- a/microsphere-spring-context/src/main/java/io/microsphere/spring/core/convert/support/ConversionServiceResolver.java +++ b/microsphere-spring-context/src/main/java/io/microsphere/spring/core/convert/support/ConversionServiceResolver.java @@ -26,7 +26,7 @@ import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.spring.beans.BeanUtils.getBeanIfAvailable; import static io.microsphere.spring.beans.BeanUtils.isBeanPresent; -import static java.lang.String.format; +import static io.microsphere.text.FormatUtils.format; import static org.springframework.context.ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME; import static org.springframework.context.ConfigurableApplicationContext.ENVIRONMENT_BEAN_NAME; @@ -67,12 +67,12 @@ public ConversionService resolve(boolean requireToRegister) { } if (conversionService == null) { // If not found, try to get the bean from BeanFactory - debug("The conversionService instance can't be found in Spring ConfigurableBeanFactory.getConversionService()"); + trace("The conversionService instance can't be found in Spring ConfigurableBeanFactory.getConversionService()"); conversionService = getFromEnvironment(); } if (conversionService == null) { // If not found, try to get the bean from ConfigurableEnvironment - debug("The conversionService instance can't be found in Spring ConfigurableEnvironment.getConversionService()"); + trace("The conversionService instance can't be found in Spring ConfigurableEnvironment.getConversionService()"); conversionService = getIfAvailable(); } if (conversionService == null) { // If not found, will create an instance of ConversionService as default @@ -117,7 +117,7 @@ protected ConversionService createDefaultConversionService() { return new DefaultFormattingConversionService(); } - private void debug(String message, Object... args) { + private void trace(String message, Object... args) { if (logger.isTraceEnabled()) { logger.trace(args.length < 1 ? message : format(message, args)); } diff --git a/microsphere-spring-context/src/test/java/io/microsphere/spring/util/BeanInitializerTest.java b/microsphere-spring-context/src/test/java/io/microsphere/spring/util/BeanInitializerTest.java index 8fcfcfe6..a6c26a3f 100644 --- a/microsphere-spring-context/src/test/java/io/microsphere/spring/util/BeanInitializerTest.java +++ b/microsphere-spring-context/src/test/java/io/microsphere/spring/util/BeanInitializerTest.java @@ -76,8 +76,8 @@ public void testRegisterSpringFactoriesBeans() { assertEquals(2, registerSpringFactoriesBeans((BeanDefinitionRegistry) registry, Bean.class)); assertTrue(registry.containsBeanDefinition("testBean")); assertTrue(registry.containsBeanDefinition("testBean2")); - assertEquals(TestBean.class,registry.getBean("testBean").getClass()); - assertEquals(TestBean2.class,registry.getBean("testBean2").getClass()); + assertEquals(TestBean.class, registry.getBean("testBean").getClass()); + assertEquals(TestBean2.class, registry.getBean("testBean2").getClass()); } } diff --git a/microsphere-spring-jdbc/src/main/java/io/microsphere/spring/jdbc/p6spy/annotation/P6DataSourceBeanDefinitionRegistrar.java b/microsphere-spring-jdbc/src/main/java/io/microsphere/spring/jdbc/p6spy/annotation/P6DataSourceBeanDefinitionRegistrar.java index b105b122..91ed4c37 100644 --- a/microsphere-spring-jdbc/src/main/java/io/microsphere/spring/jdbc/p6spy/annotation/P6DataSourceBeanDefinitionRegistrar.java +++ b/microsphere-spring-jdbc/src/main/java/io/microsphere/spring/jdbc/p6spy/annotation/P6DataSourceBeanDefinitionRegistrar.java @@ -19,7 +19,6 @@ import com.p6spy.engine.spy.P6Factory; import com.p6spy.engine.spy.P6ModuleManager; import com.p6spy.engine.spy.option.P6OptionChangedListener; -import io.microsphere.spring.beans.factory.support.BeanRegistrar; import io.microsphere.spring.jdbc.p6spy.beans.factory.CompoundJdbcEventListenerFactory; import io.microsphere.spring.jdbc.p6spy.beans.factory.config.P6DataSourceBeanPostProcessor; import org.springframework.beans.BeansException; @@ -34,6 +33,8 @@ import java.util.List; import static io.microsphere.spring.beans.BeanUtils.getSortedBeans; +import static io.microsphere.spring.beans.factory.BeanFactoryUtils.asConfigurableListableBeanFactory; +import static io.microsphere.spring.beans.factory.support.BeanRegistrar.registerBeanDefinition; /** * The {@link ImportBeanDefinitionRegistrar} class to register {@link BeanDefinition BeanDefinitions} @@ -45,12 +46,12 @@ class P6DataSourceBeanDefinitionRegistrar implements ImportBeanDefinitionRegistr @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { - BeanRegistrar.registerBeanDefinition(registry, P6DataSourceBeanPostProcessor.class); + registerBeanDefinition(registry, P6DataSourceBeanPostProcessor.class); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - initP6ModuleManager((ConfigurableListableBeanFactory) beanFactory); + initP6ModuleManager(asConfigurableListableBeanFactory(beanFactory)); } private void initP6ModuleManager(ConfigurableListableBeanFactory beanFactory) { diff --git a/microsphere-spring-parent/pom.xml b/microsphere-spring-parent/pom.xml index c267e7d2..b259c826 100644 --- a/microsphere-spring-parent/pom.xml +++ b/microsphere-spring-parent/pom.xml @@ -27,6 +27,7 @@ 1.5.15 5.11.4 5.14.2 + 1.5.3 @@ -82,6 +83,13 @@ import + + + org.skyscreamer + jsonassert + ${jsonassert.version} + + org.slf4j diff --git a/microsphere-spring-web/src/main/java/io/microsphere/spring/web/event/WebEventPublisher.java b/microsphere-spring-web/src/main/java/io/microsphere/spring/web/event/WebEventPublisher.java index ef841ea6..39f5a19c 100644 --- a/microsphere-spring-web/src/main/java/io/microsphere/spring/web/event/WebEventPublisher.java +++ b/microsphere-spring-web/src/main/java/io/microsphere/spring/web/event/WebEventPublisher.java @@ -54,11 +54,6 @@ public void beforeExecute(HandlerMethod handlerMethod, Object[] args, NativeWebR context.publishEvent(new HandlerMethodArgumentsResolvedEvent(request, handlerMethod, args)); } - @Override - public void afterExecute(HandlerMethod handlerMethod, Object[] args, Object returnValue, Throwable error, NativeWebRequest request) throws Exception { - // DO NOTHING - } - @Override protected void doStart() { WebEndpointMappingRegistry webEndpointMappingRegistry = context.getBean(WebEndpointMappingRegistry.class); diff --git a/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodAdvice.java b/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodAdvice.java index bc20c6f9..5eb5dd54 100644 --- a/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodAdvice.java +++ b/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodAdvice.java @@ -41,8 +41,9 @@ public interface HandlerMethodAdvice { * @param webRequest the current request * @throws Exception in case of errors with the preparation of argument values */ - void beforeResolveArgument(MethodParameter parameter, HandlerMethod handlerMethod, NativeWebRequest webRequest) - throws Exception; + default void beforeResolveArgument(MethodParameter parameter, HandlerMethod handlerMethod, NativeWebRequest webRequest) + throws Exception { + } /** * callback after the {@link MethodParameter} being resolved @@ -54,8 +55,9 @@ void beforeResolveArgument(MethodParameter parameter, HandlerMethod handlerMetho * @return the resolved argument value, or {@code null} if not resolvable * @throws Exception in case of errors with the preparation of argument values */ - void afterResolveArgument(MethodParameter parameter, Object resolvedArgument, HandlerMethod handlerMethod, - NativeWebRequest webRequest) throws Exception; + default void afterResolveArgument(MethodParameter parameter, Object resolvedArgument, HandlerMethod handlerMethod, + NativeWebRequest webRequest) throws Exception { + } /** * Interception point before the execution of a {@link HandlerMethod}. Called after @@ -67,7 +69,8 @@ void afterResolveArgument(MethodParameter parameter, Object resolvedArgument, Ha * @param request {@link WebRequest} * @throws Exception if any error caused */ - void beforeExecuteMethod(HandlerMethod handlerMethod, Object[] args, NativeWebRequest request) throws Exception; + default void beforeExecuteMethod(HandlerMethod handlerMethod, Object[] args, NativeWebRequest request) throws Exception { + } /** * Interception point after successful execution of a {@link HandlerMethod}. @@ -80,7 +83,8 @@ void afterResolveArgument(MethodParameter parameter, Object resolvedArgument, Ha * @param request {@link WebRequest} * @throws Exception if any error caused */ - void afterExecuteMethod(HandlerMethod handlerMethod, Object[] args, @Nullable Object returnValue, @Nullable Throwable error, - NativeWebRequest request) throws Exception; + default void afterExecuteMethod(HandlerMethod handlerMethod, Object[] args, @Nullable Object returnValue, @Nullable Throwable error, + NativeWebRequest request) throws Exception { + } } diff --git a/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodArgumentInterceptor.java b/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodArgumentInterceptor.java index 130c6de8..5799a90a 100644 --- a/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodArgumentInterceptor.java +++ b/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodArgumentInterceptor.java @@ -20,7 +20,6 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.HandlerMethod; - /** * The interceptor interface for the resolvable {@link HandlerMethod HandlerMethods'} {@link MethodParameter} * @@ -39,8 +38,9 @@ public interface HandlerMethodArgumentInterceptor { * @param webRequest the current request * @throws Exception in case of errors with the preparation of argument values */ - void beforeResolveArgument(MethodParameter parameter, HandlerMethod handlerMethod, NativeWebRequest webRequest) - throws Exception; + default void beforeResolveArgument(MethodParameter parameter, HandlerMethod handlerMethod, NativeWebRequest webRequest) + throws Exception { + } /** * callback after the {@link MethodParameter} being resolved @@ -52,8 +52,8 @@ void beforeResolveArgument(MethodParameter parameter, HandlerMethod handlerMetho * @return the resolved argument value, or {@code null} if not resolvable * @throws Exception in case of errors with the preparation of argument values */ - void afterResolveArgument(MethodParameter parameter, Object resolvedArgument, HandlerMethod handlerMethod, - NativeWebRequest webRequest) throws Exception; - + default void afterResolveArgument(MethodParameter parameter, Object resolvedArgument, HandlerMethod handlerMethod, + NativeWebRequest webRequest) throws Exception { + } -} +} \ No newline at end of file diff --git a/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodInterceptor.java b/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodInterceptor.java index 98749a32..16d8d011 100644 --- a/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodInterceptor.java +++ b/microsphere-spring-web/src/main/java/io/microsphere/spring/web/method/support/HandlerMethodInterceptor.java @@ -37,7 +37,8 @@ public interface HandlerMethodInterceptor { * @param request {@link WebRequest} * @throws Exception if any error caused */ - void beforeExecute(HandlerMethod handlerMethod, Object[] args, NativeWebRequest request) throws Exception; + default void beforeExecute(HandlerMethod handlerMethod, Object[] args, NativeWebRequest request) throws Exception { + } /** * Interception point after successful execution of a {@link HandlerMethod}. @@ -50,7 +51,8 @@ public interface HandlerMethodInterceptor { * @param request {@link WebRequest} * @throws Exception if any error caused */ - void afterExecute(HandlerMethod handlerMethod, Object[] args, @Nullable Object returnValue, @Nullable Throwable error, - NativeWebRequest request) throws Exception; + default void afterExecute(HandlerMethod handlerMethod, Object[] args, @Nullable Object returnValue, @Nullable Throwable error, + NativeWebRequest request) throws Exception { + } } diff --git a/microsphere-spring-webmvc/pom.xml b/microsphere-spring-webmvc/pom.xml index 388db38a..488d8c28 100644 --- a/microsphere-spring-webmvc/pom.xml +++ b/microsphere-spring-webmvc/pom.xml @@ -75,6 +75,12 @@ test + + org.skyscreamer + jsonassert + test + + ch.qos.logback logback-classic diff --git a/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/advice/StoringResponseBodyReturnValueAdvice.java b/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/advice/StoringResponseBodyReturnValueAdvice.java index a056c7e3..0a293958 100644 --- a/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/advice/StoringResponseBodyReturnValueAdvice.java +++ b/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/advice/StoringResponseBodyReturnValueAdvice.java @@ -8,6 +8,7 @@ import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.HandlerMethod; import java.lang.reflect.Method; @@ -15,7 +16,7 @@ import static io.microsphere.spring.webmvc.util.WebMvcUtils.supportedConverterTypes; /** - * Store {@ link HandlerMethod} return value {@ link ResponseBodyAdviceAdapter} + * Store {@link HandlerMethod} return value {@link ResponseBodyAdviceAdapter} * * @author Mercy * @since 1.0.0 diff --git a/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtension.java b/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtension.java index 0efdbd97..b288cd56 100644 --- a/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtension.java +++ b/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtension.java @@ -103,14 +103,24 @@ boolean publishEvents() default true; /** - * Indicate whether the {@link InterceptorRegistry} registers the beans of {@link HandlerInterceptor} - * by the specified types + * Indicate whether the {@link InterceptorRegistry} registers the beans of {@link HandlerInterceptor}. + * If it specifies true, {@link #handlerInterceptors()} method will not work anymore. * * @return false as default * @see WebMvcConfigurer#addInterceptors(InterceptorRegistry) * @see InterceptorRegistry */ - Class[] registerHandlerInterceptors() default {}; + boolean registerHandlerInterceptors() default false; + + /** + * Specify {@link HandlerInterceptor} types or its inherited types to register into {@link InterceptorRegistry}. + * If {@link #registerHandlerInterceptors()} is true, specified types will be ignored. + * + * @return null as default + * @see WebMvcConfigurer#addInterceptors(InterceptorRegistry) + * @see InterceptorRegistry + */ + Class[] handlerInterceptors() default {}; /** * Indicate that Stores the {@link MethodParameter argument} of {@link HandlerMethod} that annotated {@link RequestBody} diff --git a/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/WebMvcExtensionBeanDefinitionRegistrar.java b/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/WebMvcExtensionBeanDefinitionRegistrar.java index 24c9d58f..8180db5c 100644 --- a/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/WebMvcExtensionBeanDefinitionRegistrar.java +++ b/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/WebMvcExtensionBeanDefinitionRegistrar.java @@ -16,6 +16,7 @@ */ package io.microsphere.spring.webmvc.annotation; +import io.microsphere.logging.Logger; import io.microsphere.spring.web.annotation.EnableWebExtension; import io.microsphere.spring.web.annotation.WebExtensionBeanDefinitionRegistrar; import io.microsphere.spring.webmvc.advice.StoringRequestBodyArgumentAdvice; @@ -30,10 +31,14 @@ import org.springframework.core.type.AnnotationMetadata; import org.springframework.web.servlet.HandlerInterceptor; +import java.util.Arrays; + +import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.spring.beans.factory.support.BeanRegistrar.registerBeanDefinition; import static io.microsphere.spring.core.annotation.AnnotationUtils.getAnnotationAttributes; import static io.microsphere.spring.webmvc.interceptor.LazyCompositeHandlerInterceptor.BEAN_NAME; import static io.microsphere.util.ArrayUtils.isNotEmpty; +import static io.microsphere.util.ArrayUtils.of; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; /** @@ -47,10 +52,14 @@ */ public class WebMvcExtensionBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { + private static final Logger logger = getLogger(WebMvcExtensionBeanDefinitionRegistrar.class); + public static final Class ANNOTATION_CLASS = EnableWebMvcExtension.class; public static final String ANNOTATION_CLASS_NAME = ANNOTATION_CLASS.getName(); + private static final Class[] ALL_HANDLER_INTERCEPTOR_CLASSES = of(HandlerInterceptor.class); + @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { @@ -73,6 +82,9 @@ private void registerWebEndpointMappingRegistrar(AnnotationAttributes attributes if (registerWebEndpointMappings) { registerBeanDefinition(registry, WebEndpointMappingRegistrar.class); } + if (logger.isTraceEnabled()) { + logger.trace("@EnableWebMvcExtension.registerWebEndpointMappings = {}", registerWebEndpointMappings); + } } private void registerInterceptingHandlerMethodProcessor(AnnotationAttributes attributes, BeanDefinitionRegistry registry) { @@ -81,6 +93,9 @@ private void registerInterceptingHandlerMethodProcessor(AnnotationAttributes att String beanName = InterceptingHandlerMethodProcessor.BEAN_NAME; registerBeanDefinition(registry, beanName, InterceptingHandlerMethodProcessor.class); } + if (logger.isTraceEnabled()) { + logger.trace("@EnableWebMvcExtension.interceptHandlerMethods() = {}", interceptHandlerMethods); + } } private AnnotationAttributes getAttributes(AnnotationMetadata metadata) { @@ -88,13 +103,26 @@ private AnnotationAttributes getAttributes(AnnotationMetadata metadata) { } private void registerHandlerInterceptors(AnnotationAttributes attributes, BeanDefinitionRegistry registry) { - Class[] interceptorClasses = (Class[]) attributes.getClassArray("registerHandlerInterceptors"); + Class[] interceptorClasses = resolveHandlerInterceptorClasses(attributes); if (isNotEmpty(interceptorClasses)) { registerLazyCompositeHandlerInterceptor(registry, interceptorClasses); registerInterceptors(registry, interceptorClasses); } } + private Class[] resolveHandlerInterceptorClasses(AnnotationAttributes attributes) { + boolean registerHandlerInterceptors = attributes.getBoolean("registerHandlerInterceptors"); + Class[] handlerInterceptors = + (Class[]) attributes.getClassArray("handlerInterceptors"); + Class[] handlerInterceptorClasses = registerHandlerInterceptors ? + ALL_HANDLER_INTERCEPTOR_CLASSES : handlerInterceptors; + if (logger.isTraceEnabled()) { + logger.trace("@EnableWebMvcExtension.registerHandlerInterceptors() = {} , handlerInterceptors() = {} , handlerInterceptorClasses = {}", + registerHandlerInterceptors, handlerInterceptors, handlerInterceptorClasses); + } + return handlerInterceptorClasses; + } + private void registerLazyCompositeHandlerInterceptor(BeanDefinitionRegistry registry, Class... interceptorClasses) { AbstractBeanDefinition beanDefinition = rootBeanDefinition(LazyCompositeHandlerInterceptor.class) .addConstructorArgValue(interceptorClasses) @@ -103,6 +131,9 @@ private void registerLazyCompositeHandlerInterceptor(BeanDefinitionRegistry regi } private void registerInterceptors(BeanDefinitionRegistry registry, Class[] interceptorClasses) { + if (Arrays.equals(ALL_HANDLER_INTERCEPTOR_CLASSES, interceptorClasses)) { + return; + } for (Class interceptorClass : interceptorClasses) { registerInterceptor(registry, interceptorClass); } @@ -117,6 +148,9 @@ private void registerStoringRequestBodyArgumentAdvice(AnnotationAttributes attri if (storeRequestBodyArgument) { registerBeanDefinition(registry, StoringRequestBodyArgumentAdvice.class); } + if (logger.isTraceEnabled()) { + logger.trace("@EnableWebMvcExtension.storeRequestBodyArgument() = {}", storeRequestBodyArgument); + } } private void registerStoringResponseBodyReturnValueAdvice(AnnotationAttributes attributes, BeanDefinitionRegistry registry) { @@ -124,5 +158,8 @@ private void registerStoringResponseBodyReturnValueAdvice(AnnotationAttributes a if (storeResponseBodyReturnValue) { registerBeanDefinition(registry, StoringResponseBodyReturnValueAdvice.class); } + if (logger.isTraceEnabled()) { + logger.trace("@EnableWebMvcExtension.storeResponseBodyReturnValue() = {}", storeResponseBodyReturnValue); + } } } diff --git a/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/WebMvcExtensionConfiguration.java b/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/WebMvcExtensionConfiguration.java index 5dce22e4..9351c226 100644 --- a/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/WebMvcExtensionConfiguration.java +++ b/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/annotation/WebMvcExtensionConfiguration.java @@ -16,12 +16,14 @@ */ package io.microsphere.spring.webmvc.annotation; +import io.microsphere.logging.Logger; import io.microsphere.spring.webmvc.interceptor.LazyCompositeHandlerInterceptor; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import static io.microsphere.logging.LoggerFactory.getLogger; +import static io.microsphere.util.ArrayUtils.length; /** * The configuration class for {@link EnableWebMvcExtension} @@ -33,13 +35,29 @@ */ public class WebMvcExtensionConfiguration implements WebMvcConfigurer { - @Autowired - private ObjectProvider lazyCompositeHandlerInterceptorProvider; + private static final Logger logger = getLogger(WebMvcExtensionConfiguration.class); + + private final ObjectProvider lazyCompositeHandlerInterceptorProvider; + + public WebMvcExtensionConfiguration(ObjectProvider lazyCompositeHandlerInterceptorProvider) { + this.lazyCompositeHandlerInterceptorProvider = lazyCompositeHandlerInterceptorProvider; + } @Override public void addInterceptors(InterceptorRegistry registry) { LazyCompositeHandlerInterceptor[] lazyCompositeHandlerInterceptors = lazyCompositeHandlerInterceptorProvider.getIfAvailable(); - for (LazyCompositeHandlerInterceptor lazyCompositeHandlerInterceptor : lazyCompositeHandlerInterceptors) { + int length = length(lazyCompositeHandlerInterceptors); + if (length == 0) { + if (logger.isTraceEnabled()) { + logger.trace("No LazyCompositeHandlerInterceptor Bean was registered."); + } + return; + } + if (logger.isTraceEnabled()) { + logger.trace("{} LazyCompositeHandlerInterceptor Beans will be added into InterceptorRegistry.", length); + } + for (int i = 0; i < length; i++) { + LazyCompositeHandlerInterceptor lazyCompositeHandlerInterceptor = lazyCompositeHandlerInterceptors[i]; registry.addInterceptor(lazyCompositeHandlerInterceptor); } } diff --git a/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/interceptor/LazyCompositeHandlerInterceptor.java b/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/interceptor/LazyCompositeHandlerInterceptor.java index bff248e7..b575fb52 100644 --- a/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/interceptor/LazyCompositeHandlerInterceptor.java +++ b/microsphere-spring-webmvc/src/main/java/io/microsphere/spring/webmvc/interceptor/LazyCompositeHandlerInterceptor.java @@ -84,7 +84,12 @@ protected void onApplicationContextEvent(ContextRefreshedEvent event) { List allInterceptors = new LinkedList<>(); for (Class interceptorClass : interceptorClasses) { Collection interceptors = context.getBeansOfType(interceptorClass).values(); - allInterceptors.addAll(interceptors); + for (HandlerInterceptor interceptor : interceptors) { + if (interceptor == this) { + continue; + } + allInterceptors.add(interceptor); + } } sort(allInterceptors); this.interceptors = allInterceptors; diff --git a/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/AbstractEnableWebMvcExtensionTest.java b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/AbstractEnableWebMvcExtensionTest.java new file mode 100644 index 00000000..4130381b --- /dev/null +++ b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/AbstractEnableWebMvcExtensionTest.java @@ -0,0 +1,229 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 io.microsphere.spring.webmvc.annotation; + +import io.microsphere.spring.web.event.HandlerMethodArgumentsResolvedEvent; +import io.microsphere.spring.web.event.WebEndpointMappingsReadyEvent; +import io.microsphere.spring.web.event.WebEventPublisher; +import io.microsphere.spring.web.metadata.SimpleWebEndpointMappingRegistry; +import io.microsphere.spring.web.metadata.WebEndpointMapping; +import io.microsphere.spring.web.method.support.DelegatingHandlerMethodAdvice; +import io.microsphere.spring.web.method.support.HandlerMethodArgumentInterceptor; +import io.microsphere.spring.webmvc.advice.StoringRequestBodyArgumentAdvice; +import io.microsphere.spring.webmvc.advice.StoringResponseBodyReturnValueAdvice; +import io.microsphere.spring.webmvc.controller.TestController; +import io.microsphere.spring.webmvc.interceptor.LazyCompositeHandlerInterceptor; +import io.microsphere.spring.webmvc.metadata.WebEndpointMappingRegistrar; +import io.microsphere.spring.webmvc.method.support.InterceptingHandlerMethodProcessor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Import; +import org.springframework.context.event.EventListener; +import org.springframework.core.MethodParameter; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.context.ConfigurableWebApplicationContext; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import java.lang.reflect.Method; +import java.util.Collection; + +import static io.microsphere.spring.beans.BeanUtils.isBeanPresent; +import static io.microsphere.util.ArrayUtils.isNotEmpty; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; + +/** + * Abstract {@link EnableWebMvcExtension} Test + * + * @author Mercy + * @see EnableWebMvcExtension + * @since 1.0.0 + */ +@ExtendWith(SpringExtension.class) +@WebAppConfiguration +@EnableWebMvc +@Disabled +@Import(TestController.class) +abstract class AbstractEnableWebMvcExtensionTest implements HandlerMethodArgumentInterceptor { + + @Autowired + protected ConfigurableWebApplicationContext wac; + + protected MockMvc mockMvc; + + protected boolean registerWebEndpointMappings; + + protected boolean interceptHandlerMethods; + + protected boolean publishEvents; + + protected boolean registerHandlerInterceptors; + + protected boolean storeRequestBodyArgument; + + protected boolean storeResponseBodyReturnValue; + + @BeforeEach + public void setup() { + this.mockMvc = webAppContextSetup(this.wac).build(); + EnableWebMvcExtension enableWebMvcExtension = this.getClass().getAnnotation(EnableWebMvcExtension.class); + this.registerWebEndpointMappings = enableWebMvcExtension.registerWebEndpointMappings(); + this.interceptHandlerMethods = enableWebMvcExtension.interceptHandlerMethods(); + this.publishEvents = enableWebMvcExtension.publishEvents(); + this.registerHandlerInterceptors = enableWebMvcExtension.registerHandlerInterceptors() ? true : + isNotEmpty(enableWebMvcExtension.handlerInterceptors()); + this.storeRequestBodyArgument = enableWebMvcExtension.storeRequestBodyArgument(); + this.storeResponseBodyReturnValue = enableWebMvcExtension.storeResponseBodyReturnValue(); + } + + @Test + public void testRegisteredBeans() { + assertTrue(isBeanPresent(this.wac, WebMvcExtensionConfiguration.class)); + // From @EnableWebExtension + assertEquals(this.registerWebEndpointMappings, isBeanPresent(this.wac, SimpleWebEndpointMappingRegistry.class)); + assertEquals(this.interceptHandlerMethods, this.wac.containsBean(DelegatingHandlerMethodAdvice.BEAN_NAME)); + assertEquals(this.publishEvents, isBeanPresent(this.wac, WebEventPublisher.class)); + + // From @EnableWebMvcExtension + assertEquals(this.registerWebEndpointMappings, isBeanPresent(this.wac, WebEndpointMappingRegistrar.class)); + assertEquals(this.interceptHandlerMethods, isBeanPresent(this.wac, DelegatingHandlerMethodAdvice.class)); + assertEquals(this.interceptHandlerMethods, this.wac.containsBean(InterceptingHandlerMethodProcessor.BEAN_NAME)); + assertEquals(this.interceptHandlerMethods, isBeanPresent(this.wac, InterceptingHandlerMethodProcessor.class)); + assertEquals(this.registerHandlerInterceptors, isBeanPresent(this.wac, LazyCompositeHandlerInterceptor.class)); + assertEquals(this.storeRequestBodyArgument, isBeanPresent(this.wac, StoringRequestBodyArgumentAdvice.class)); + assertEquals(this.storeResponseBodyReturnValue, isBeanPresent(this.wac, StoringResponseBodyReturnValueAdvice.class)); + } + + @Test + public void test() throws Exception { + this.mockMvc.perform(get("/echo/hello")) + .andExpect(status().isOk()) + .andExpect(content().json("[ECHO] : hello")); + } + + /** + * Test only one mapping : {@link TestController#echo(String)} + * + * @param event {@link WebEndpointMappingsReadyEvent} + */ + @EventListener(WebEndpointMappingsReadyEvent.class) + public void onWebEndpointMappingsReadyEvent(WebEndpointMappingsReadyEvent event) { + // Only TestController + Collection mappings = event.getMappings(); + assertEquals(1, mappings.size()); + WebEndpointMapping webEndpointMapping = mappings.iterator().next(); + String[] patterns = webEndpointMapping.getPatterns(); + assertEquals(1, patterns.length); + assertEquals("/echo/{message}", patterns[0]); + } + + /** + * Test only one method : {@link TestController#echo(String)} + * + * @param event {@link HandlerMethodArgumentsResolvedEvent} + */ + @EventListener(HandlerMethodArgumentsResolvedEvent.class) + public void onHandlerMethodArgumentsResolvedEvent(HandlerMethodArgumentsResolvedEvent event) { + Method method = event.getMethod(); + assertMethod(method); + + HandlerMethod handlerMethod = event.getHandlerMethod(); + assertEquals(method, handlerMethod.getMethod()); + + assertHandlerMethod(handlerMethod); + + Object[] arguments = event.getArguments(); + assertArguments(arguments); + } + + /** + * callback before the {@link MethodParameter} being resolved + * + * @param parameter the method parameter to resolve. + * @param handlerMethod the method to handle + * @param webRequest the current request + * @throws Exception in case of errors with the preparation of argument values + */ + @Override + public void beforeResolveArgument(MethodParameter parameter, HandlerMethod handlerMethod, NativeWebRequest webRequest) throws Exception { + assertMethodParameter(parameter); + assertHandlerMethod(handlerMethod); + assertNativeWebRequest(webRequest); + } + + /** + * callback after the {@link MethodParameter} being resolved + * + * @param parameter the method parameter to resolve. + * @param resolvedArgument the resolved argument + * @param handlerMethod the method to handle + * @param webRequest the current request + * @return the resolved argument value, or {@code null} if not resolvable + * @throws Exception in case of errors with the preparation of argument values + */ + @Override + public void afterResolveArgument(MethodParameter parameter, Object resolvedArgument, HandlerMethod handlerMethod, NativeWebRequest webRequest) throws Exception { + // Reuse + beforeResolveArgument(parameter, handlerMethod, webRequest); + assertEquals("hello", resolvedArgument); + } + + private void assertMethod(Method method) { + assertEquals("echo", method.getName()); + assertEquals(String.class, method.getReturnType()); + + Class[] parameterTypes = method.getParameterTypes(); + assertEquals(1, parameterTypes.length); + assertEquals(String.class, parameterTypes[0]); + } + + private void assertHandlerMethod(HandlerMethod handlerMethod) { + assertNotNull(handlerMethod); + Object bean = handlerMethod.getBean(); + assertNotNull(bean); + assertEquals(TestController.class, bean.getClass()); + assertMethod(handlerMethod.getMethod()); + } + + private void assertArguments(Object[] arguments) { + assertEquals(1, arguments.length); + assertEquals("hello", arguments[0]); + } + + private void assertMethodParameter(MethodParameter parameter) { + assertNotNull(parameter); + assertEquals(0, parameter.getParameterIndex()); + assertEquals(String.class, parameter.getParameterType()); + } + + private void assertNativeWebRequest(NativeWebRequest webRequest) { + } + + +} diff --git a/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionDefaultsTest.java b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionDefaultsTest.java new file mode 100644 index 00000000..771953dc --- /dev/null +++ b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionDefaultsTest.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 io.microsphere.spring.webmvc.annotation; + +import org.springframework.test.context.ContextConfiguration; + +/** + * {@link EnableWebMvcExtension} Test with defaults + * + * @author Mercy + * @see EnableWebMvcExtension + * @since 1.0.0 + */ +@ContextConfiguration(classes = { + EnableWebMvcExtensionDefaultsTest.class +}) +@EnableWebMvcExtension +public class EnableWebMvcExtensionDefaultsTest extends AbstractEnableWebMvcExtensionTest { +} diff --git a/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionDisableTest.java b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionDisableTest.java new file mode 100644 index 00000000..7f413bad --- /dev/null +++ b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionDisableTest.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 io.microsphere.spring.webmvc.annotation; + +import org.springframework.test.context.ContextConfiguration; + +/** + * {@link EnableWebMvcExtension} Test with disable features + * + * @author Mercy + * @see EnableWebMvcExtension + * @since 1.0.0 + */ +@ContextConfiguration(classes = { + EnableWebMvcExtensionDisableTest.class +}) +@EnableWebMvcExtension( + registerWebEndpointMappings = false, + interceptHandlerMethods = false, + publishEvents = false +) +public class EnableWebMvcExtensionDisableTest extends AbstractEnableWebMvcExtensionTest { +} diff --git a/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionInterceptorsTest.java b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionInterceptorsTest.java new file mode 100644 index 00000000..acb0c640 --- /dev/null +++ b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionInterceptorsTest.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 io.microsphere.spring.webmvc.annotation; + +import io.microsphere.spring.webmvc.interceptor.IdempotentAnnotatedMethodHandlerInterceptor; +import org.junit.jupiter.api.Test; +import org.springframework.test.context.ContextConfiguration; + +import static io.microsphere.spring.webmvc.interceptor.IdempotentAnnotatedMethodHandlerInterceptor.MOCK_TOKEN_VALUE; +import static io.microsphere.spring.webmvc.interceptor.IdempotentAnnotatedMethodHandlerInterceptor.TOKEN_HEADER_NAME; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * {@link EnableWebMvcExtension} Test with interceptors + * + * @author Mercy + * @see EnableWebMvcExtension + * @since 1.0.0 + */ +@ContextConfiguration(classes = { + EnableWebMvcExtensionInterceptorsTest.class +}) +@EnableWebMvcExtension(handlerInterceptors = { + IdempotentAnnotatedMethodHandlerInterceptor.class +}) +public class EnableWebMvcExtensionInterceptorsTest extends AbstractEnableWebMvcExtensionTest { + + @Test + @Override + public void test() throws Exception { + this.mockMvc.perform(get("/echo/hello").header(TOKEN_HEADER_NAME, MOCK_TOKEN_VALUE)) + .andExpect(status().isOk()) + .andExpect(content().json("[ECHO] : hello")); + } +} diff --git a/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionTest.java b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionTest.java new file mode 100644 index 00000000..84071f87 --- /dev/null +++ b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/annotation/EnableWebMvcExtensionTest.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 io.microsphere.spring.webmvc.annotation; + +import org.springframework.test.context.ContextConfiguration; + +/** + * {@link EnableWebMvcExtension} Test + * + * @author Mercy + * @see EnableWebMvcExtension + * @since 1.0.0 + */ +@ContextConfiguration(classes = { + EnableWebMvcExtensionTest.class +}) +@EnableWebMvcExtension( + registerHandlerInterceptors = true, + storeRequestBodyArgument = true, + storeResponseBodyReturnValue = true +) +public class EnableWebMvcExtensionTest extends AbstractEnableWebMvcExtensionTest { +} diff --git a/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/interceptor/IdempotentAnnotatedMethodHandlerInterceptor.java b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/interceptor/IdempotentAnnotatedMethodHandlerInterceptor.java index 74ca9234..4fbbf4f5 100644 --- a/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/interceptor/IdempotentAnnotatedMethodHandlerInterceptor.java +++ b/microsphere-spring-webmvc/src/test/java/io/microsphere/spring/webmvc/interceptor/IdempotentAnnotatedMethodHandlerInterceptor.java @@ -16,19 +16,23 @@ */ package io.microsphere.spring.webmvc.interceptor; +import io.microsphere.logging.Logger; import io.microsphere.spring.web.event.HandlerMethodArgumentsResolvedEvent; import io.microsphere.spring.webmvc.IdempotentException; import io.microsphere.spring.webmvc.annotation.Idempotent; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.HttpSession; import org.springframework.context.ApplicationListener; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.method.HandlerMethod; import java.lang.reflect.Method; -import java.util.Arrays; +import java.util.Objects; +import java.util.UUID; + +import static io.microsphere.logging.LoggerFactory.getLogger; +import static java.util.Arrays.asList; /** * {@link AnnotatedMethodHandlerInterceptor} for {@link Idempotent} annotation @@ -36,15 +40,18 @@ * @author Mercy * @since 1.0.0 */ -public class IdempotentAnnotatedMethodHandlerInterceptor extends AnnotatedMethodHandlerInterceptor implements ApplicationListener { +public class IdempotentAnnotatedMethodHandlerInterceptor extends AnnotatedMethodHandlerInterceptor + implements ApplicationListener { + + private static final Logger logger = getLogger(IdempotentAnnotatedMethodHandlerInterceptor.class); + + public static final String TOKEN_HEADER_NAME = "_token_"; + + public static final String MOCK_TOKEN_VALUE = UUID.randomUUID().toString(); @Override protected boolean preHandle(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod, Idempotent idempotent) throws Exception { - - System.out.println(handlerMethod); - System.out.println(idempotent); - return true; } @@ -54,18 +61,14 @@ protected boolean preHandle(HttpServletRequest request, HttpServletResponse resp public void onApplicationEvent(HandlerMethodArgumentsResolvedEvent event) { Method method = event.getMethod(); Object[] args = event.getArguments(); - System.out.println("method : " + method + " , args : " + Arrays.asList(args)); WebRequest webRequest = event.getWebRequest(); - if (webRequest instanceof ServletWebRequest servletWebRequest) { + logger.trace("The method : {} , args : {} , webRequest : {}", method, asList(args), webRequest); + if (webRequest instanceof ServletWebRequest) { + ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest; HttpServletRequest request = servletWebRequest.getNativeRequest(HttpServletRequest.class); - // HttpSession based on Spring Redis - // Spring Session - HttpSession httpSession = request.getSession(); - String token = request.getHeader("token"); - Object tokenValue = httpSession.getAttribute(token); - if (tokenValue != null) { - // - throw new IdempotentException(""); + String token = request.getHeader(TOKEN_HEADER_NAME); + if (!Objects.equals(MOCK_TOKEN_VALUE, token)) { + throw new IdempotentException("Illegal token"); } } }