All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.microsphere.spring.webmvc.util.WebMvcUtils Maven / Gradle / Ivy

package io.microsphere.spring.webmvc.util;

import io.microsphere.spring.web.servlet.util.WebUtils;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.RequestContextFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.support.RequestContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static org.springframework.util.ReflectionUtils.findMethod;
import static org.springframework.util.ReflectionUtils.invokeMethod;
import static org.springframework.web.context.ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM;
import static org.springframework.web.context.ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM;

/**
 * Spring Web MVC Utilities Class
 *
 * @author Mercy
 * @since 1.0.0
 */
@SuppressWarnings("unchecked")
public abstract class WebMvcUtils {

    public static final String HANDLER_METHOD_ARGUMENTS_ATTRIBUTE_NAME_PREFIX = "HM.ARGS:";

    public static final String HANDLER_METHOD_REQUEST_BODY_ARGUMENT_ATTRIBUTE_NAME_PREFIX = "HM.RB.ARG:";

    public static final String HANDLER_METHOD_RETURN_VALUE_ATTRIBUTE_NAME_PREFIX = "HM.RV:";

    public static final Set>> supportedConverterTypes;

    /**
     * The name of AbstractJsonpResponseBodyAdvice class which was present in Spring Framework since 4.1
     */
    public static final String ABSTRACT_JSONP_RESPONSE_BODY_ADVICE_CLASS_NAME =
            "org.springframework.web.servlet.mvc.findWebApplicationContextMethod.annotation.AbstractJsonpResponseBodyAdvice";

    /**
     * Indicates current version of Spring Framework is 4.1 or above
     */
    private final static boolean ABSTRACT_JSONP_RESPONSE_BODY_ADVICE_PRESENT =
            ClassUtils.isPresent(ABSTRACT_JSONP_RESPONSE_BODY_ADVICE_CLASS_NAME, WebMvcUtils.class.getClassLoader());

    /**
     * {@link RequestMappingHandlerMapping} Context name
     */
    private final static String REQUEST_MAPPING_HANDLER_MAPPING_CONTEXT_NAME = RequestMappingHandlerMapping.class.getName();

    /**
     * Any number of these characters are considered delimiters between
     * multiple values in a single init-param String value.
     *
     * @see ContextLoader#INIT_PARAM_DELIMITERS
     */
    private static final String INIT_PARAM_DELIMITERS = ",; \t\n";

    /**
     * RequestContextUtils#findWebApplicationContext(HttpServletRequest, ServletContext) method
     *
     * @since Spring 4.2.1
     */
    private static final Method findWebApplicationContextMethod = findMethod(RequestContextUtils.class,
            "findWebApplicationContext", HttpServletRequest.class, ServletContext.class);

    static {
        Set>> converterTypes = new HashSet<>(3);
        converterTypes.add(MappingJackson2HttpMessageConverter.class);
        converterTypes.add(StringHttpMessageConverter.class);
        supportedConverterTypes = Collections.unmodifiableSet(converterTypes);
    }

    /**
     * Gets the current {@link HttpServletRequest} object
     * 

* By default, {@link HttpServletRequest} is initialized in {@link RequestContextFilter}, {@link HttpServletRequest} * from the Servlet HTTP request thread {@link ThreadLocal} is obtained from {@link InheritableThreadLocal} and * can be obtained in the child thread. * * @return null returns the current {@link HttpServletRequest} object. */ public static HttpServletRequest getHttpServletRequest() throws IllegalStateException { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); HttpServletRequest request = null; if (requestAttributes instanceof ServletRequestAttributes) { request = ((ServletRequestAttributes) requestAttributes).getRequest(); } return request; } public static HttpServletRequest getHttpServletRequest(WebRequest webRequest) { HttpServletRequest request = null; if (webRequest instanceof ServletWebRequest) { request = ((ServletWebRequest) webRequest).getRequest(); } return request; } /** * Gets the {@link WebApplicationContext} associated with the current Servlet Request request * * @return Current Servlet Request associated with {@link WebApplicationContext} * @throws IllegalStateException In a non-Web scenario, an exception is thrown */ public static WebApplicationContext getWebApplicationContext() throws IllegalStateException { HttpServletRequest request = getHttpServletRequest(); if (request == null) { throw new IllegalStateException("Use it in your Servlet Web application!"); } ServletContext servletContext = request.getServletContext(); return WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); } /** * Set the {@link RequestBody @RequestBody} method parameter in {@link HandlerMethod} to the {@link ServletRequest} context * * @param method Handler {@link Method} * @param requestBodyArgument {@link RequestBody @RequestBody} The method parameters */ public static void setHandlerMethodRequestBodyArgument(Method method, Object requestBodyArgument) { setHandlerMethodRequestBodyArgument(getHttpServletRequest(), method, requestBodyArgument); } public static void setHandlerMethodReturnValue(HttpServletRequest request, Method method, Object returnValue) { String attributeName = getHandlerMethodReturnValueAttributeName(method); if (request != null && returnValue != null) { request.setAttribute(attributeName, returnValue); } } /** * Set the {@link RequestBody @RequestBody} method parameter in {@link HandlerMethod} to the {@link ServletRequest} context * * @param request {@link ServletRequest} * @param method Handler {@link Method} * @param requestBodyArgument {@link RequestBody @RequestBody} The method parameters */ public static void setHandlerMethodRequestBodyArgument(ServletRequest request, Method method, Object requestBodyArgument) { String attributeName = getHandlerMethodRequestBodyArgumentAttributeName(method); if (request != null && requestBodyArgument != null) { request.setAttribute(attributeName, requestBodyArgument); } } /** * Gets the {@link RequestBody @RequestBody} method parameter from the {@link ServletRequest} context * * @param request {@link ServletRequest} * @param handlerMethod {@link HandlerMethod} * @param {@link RequestBody @RequestBody} Method parameter Types * @return {@link RequestBody @RequestBody} Method parameters if present, otherwise,null */ public static T getHandlerMethodRequestBodyArgument(ServletRequest request, HandlerMethod handlerMethod) { return getHandlerMethodRequestBodyArgument(request, handlerMethod.getMethod()); } /** * Gets the {@link RequestBody @RequestBody} method parameter from the {@link ServletRequest} context * * @param request {@link ServletRequest} * @param method Handler {@link Method} * @param {@link RequestBody @RequestBody} Method parameter Types * @return {@link RequestBody @RequestBody} method parameter if present, otherwise null */ public static T getHandlerMethodRequestBodyArgument(ServletRequest request, Method method) { String attributeName = getHandlerMethodRequestBodyArgumentAttributeName(method); return request == null ? null : (T) request.getAttribute(attributeName); } public static Object[] getHandlerMethodArguments(WebRequest webRequest, HandlerMethod handlerMethod) { Method method = handlerMethod.getMethod(); return getHandlerMethodArguments(webRequest, method); } public static Object[] getHandlerMethodArguments(WebRequest webRequest, MethodParameter parameter) { Method method = parameter.getMethod(); return getHandlerMethodArguments(webRequest, method); } public static Object[] getHandlerMethodArguments(WebRequest webRequest, Method method) { HttpServletRequest request = getHttpServletRequest(webRequest); final Object[] arguments; if (request != null) { arguments = WebMvcUtils.getHandlerMethodArguments(request, method); } else { arguments = new Object[method.getParameterCount()]; } return arguments; } /** * Gets the {@link HandlerMethod} method parameter * * @param request {@link ServletRequest} * @param handlerMethod {@link HandlerMethod} * @return non-null */ public static Object[] getHandlerMethodArguments(ServletRequest request, HandlerMethod handlerMethod) { return getHandlerMethodArguments(request, handlerMethod.getMethod()); } /** * Gets the {@link HandlerMethod} method parameter * * @param request {@link ServletRequest} * @param method {@link Method} * @return non-null */ public static Object[] getHandlerMethodArguments(ServletRequest request, Method method) { String attributeName = getHandlerMethodArgumentsAttributeName(method); Object[] arguments = (Object[]) request.getAttribute(attributeName); if (arguments == null) { arguments = new Object[method.getParameterCount()]; request.setAttribute(attributeName, arguments); } return arguments; } /** * Gets the {@link HandlerMethod} method parameter * * @param method {@link Method} * @return non-null */ public static Object[] getHandlerMethodArguments(Method method) { return getHandlerMethodArguments(getHttpServletRequest(), method); } /** * Gets the value returned by the {@link HandlerMethod} method * * @param request {@link ServletRequest} * @param handlerMethod {@link HandlerMethod} * @param Method return value type * @return {@link HandlerMethod} Method return value */ public static T getHandlerMethodReturnValue(ServletRequest request, HandlerMethod handlerMethod) { Method method = handlerMethod.getMethod(); return getHandlerMethodReturnValue(request, method); } /** * Gets the value returned by the {@link HandlerMethod} method * * @param request {@link ServletRequest} * @param method {@link Method} * @param Method return value type * @return {@link HandlerMethod} Method return value */ public static T getHandlerMethodReturnValue(ServletRequest request, Method method) { String attributeName = getHandlerMethodReturnValueAttributeName(method); return (T) request.getAttribute(attributeName); } /** * Gets the value returned by the {@link HandlerMethod} method * * @param method {@link Method} * @param Method return value type * @return {@link HandlerMethod} Method return value */ public static T getHandlerMethodReturnValue(Method method) { HttpServletRequest request = getHttpServletRequest(); return getHandlerMethodReturnValue(request, method); } /** * Determine whether the Bean Type is present annotated by {@link ControllerAdvice} * * @param beanType Bean Type * @return If {@link ControllerAdvice} bean type is present , return true , or false. */ public static boolean isControllerAdviceBeanType(Class beanType) { return AnnotationUtils.findAnnotation(beanType, ControllerAdvice.class) != null; } /** * Get the {@link WebApplicationContext} from {@link HttpServletRequest} * * @param request {@link HttpServletRequest} * @param servletContext {@link ServletContext} * @return {@link WebApplicationContext} * @throws IllegalStateException if no servlet-specific context has been found * @see RequestContextUtils#getWebApplicationContext(ServletRequest) * @see DispatcherServlet#WEB_APPLICATION_CONTEXT_ATTRIBUTE */ public static WebApplicationContext getWebApplicationContext(HttpServletRequest request, ServletContext servletContext) { WebApplicationContext webApplicationContext = null; if (findWebApplicationContextMethod != null) { try { webApplicationContext = (WebApplicationContext) invokeMethod(findWebApplicationContextMethod, null, request, servletContext); } catch (IllegalStateException e) { } } if (webApplicationContext == null) { webApplicationContext = RequestContextUtils.findWebApplicationContext(request, servletContext); } return webApplicationContext; } protected static String appendInitParameter(String existedParameterValue, String... parameterValues) { String[] existedParameterValues = StringUtils.hasLength(existedParameterValue) ? existedParameterValue.split(INIT_PARAM_DELIMITERS) : new String[0]; List parameterValuesList = new ArrayList(); if (!ObjectUtils.isEmpty(existedParameterValues)) { parameterValuesList.addAll(Arrays.asList(existedParameterValues)); } parameterValuesList.addAll(Arrays.asList(parameterValues)); String newParameterValue = StringUtils.arrayToDelimitedString(parameterValuesList.toArray(), ","); return newParameterValue; } /** * Append {@link ServletContext#setInitParameter(String, String) ServletContext Intialized Parameters} * * @param servletContext {@link ServletContext} * @param parameterName the name of init parameter * @param parameterValues the values of init parameters */ public static void appendInitParameters(ServletContext servletContext, String parameterName, String... parameterValues) { Assert.notNull(servletContext); Assert.hasLength(parameterName); Assert.notNull(parameterValues); String existedParameterValue = servletContext.getInitParameter(parameterName); String newParameterValue = appendInitParameter(existedParameterValue, parameterValues); if (StringUtils.hasLength(newParameterValue)) { servletContext.setInitParameter(parameterName, newParameterValue); } } /** * Append initialized parameter for {@link ApplicationContextInitializer Global Initializer Class} * * @param servletContext {@link ServletContext} * @param contextInitializerClass the class of {@link ApplicationContextInitializer} * @see ContextLoader#GLOBAL_INITIALIZER_CLASSES_PARAM */ public static void appendGlobalInitializerClassInitParameter(ServletContext servletContext, Class contextInitializerClass) { String contextInitializerClassName = contextInitializerClass.getName(); appendInitParameters(servletContext, GLOBAL_INITIALIZER_CLASSES_PARAM, contextInitializerClassName); } /** * Append initialized parameter for {@link ApplicationContextInitializer Context Initializer Class} * * @param servletContext {@link ServletContext} * @param contextInitializerClass the class of {@link ApplicationContextInitializer} * @see ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM */ public static void appendContextInitializerClassInitParameter(ServletContext servletContext, Class contextInitializerClass) { String contextInitializerClassName = contextInitializerClass.getName(); appendInitParameters(servletContext, CONTEXT_INITIALIZER_CLASSES_PARAM, contextInitializerClassName); } /** * Append initialized parameter for {@link ApplicationContextInitializer Context Initializer Class} into {@link * FrameworkServlet} * * @param servletContext {@link ServletContext} * @param contextInitializerClass the class of {@link ApplicationContextInitializer} * @see FrameworkServlet#applyInitializers(ConfigurableApplicationContext) */ public static void appendFrameworkServletContextInitializerClassInitParameter( ServletContext servletContext, Class contextInitializerClass) { Collection servletRegistrations = WebUtils.findServletRegistrations(servletContext, FrameworkServlet.class).values(); for (ServletRegistration servletRegistration : servletRegistrations) { String contextInitializerClassName = servletRegistration.getInitParameter(CONTEXT_INITIALIZER_CLASSES_PARAM); String newContextInitializerClassName = appendInitParameter(contextInitializerClassName, contextInitializerClass.getName()); servletRegistration.setInitParameter(CONTEXT_INITIALIZER_CLASSES_PARAM, newContextInitializerClassName); } } /** * Is page render request * * @param modelAndView {@link ModelAndView} * @return If current request is for page render , return true , or false. */ public static boolean isPageRenderRequest(ModelAndView modelAndView) { if (modelAndView != null) { String viewName = modelAndView.getViewName(); return StringUtils.hasText(viewName); } return false; } private static String getHandlerMethodRequestBodyArgumentAttributeName(Method method) { return HANDLER_METHOD_REQUEST_BODY_ARGUMENT_ATTRIBUTE_NAME_PREFIX + getMethodInfo(method); } private static String getHandlerMethodReturnValueAttributeName(Method method) { return HANDLER_METHOD_RETURN_VALUE_ATTRIBUTE_NAME_PREFIX + getMethodInfo(method); } private static String getHandlerMethodArgumentsAttributeName(Method method) { return HANDLER_METHOD_ARGUMENTS_ATTRIBUTE_NAME_PREFIX + getMethodInfo(method); } private static String getMethodInfo(Method method) { return String.valueOf(method); } }