在Springboot使用FastJson解析Controller传入参数


使用FastJson实现Springboot中的HandlerMethodArgumentResolver

  • 实现目的
  • 实现代码
    • FastJsonParse
    • FastJsonArgumentResolver
    • JSONObjectWrapper
    • Springboot配置
  • 使用HandlerMethodArgumentResolver解析过程分析
  • 参考

实现目的 【在Springboot使用FastJson解析Controller传入参数】使用Fastjson来解析Springboot中Controller的参数
实现代码 FastJsonParse
package com.common; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * description: FastJsonParse 注解标记的参数将使用FastJson解析 * * @date: 2020-03-31 10:04 * @author: shangjie * @version: 1.0 */ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface FastJsonParse { /** * 解析带泛型的类 * */ boolean useGenericType() default false; }

FastJsonArgumentResolver
package com.common; import com.alibaba.fastjson.JSON; import org.springframework.core.MethodParameter; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.annotation.MapMethodProcessor; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; /** * description: FastJsonArgumentResolver * * @date: 2020-03-31 10:03 * @author: shangjie * @version: 1.0 */ public class FastJsonArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(FastJsonParse.class); }@Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); // content-type不是json的不处理 if (!request.getContentType().contains("application/json")) { return null; } // 把request的body读取到StringBuilder BufferedReader reader = request.getReader(); StringBuilder sb = new StringBuilder(); char[] buf = new char[1024]; int rd; while((rd = reader.read(buf)) != -1){ sb.append(buf, 0, rd); } // 利用fastjson转换为对应的类型 if(JSONObjectWrapper.class.isAssignableFrom(parameter.getParameterType())){ return new JSONObjectWrapper(JSON.parseObject(sb.toString())); } else { // 判断是否解析的是带泛型的类 FastJsonParse fastJsonParse = parameter.getParameterAnnotation(FastJsonParse.class); if (fastJsonParse.useGenericType()) { return JSON.parseObject(sb.toString(), parameter.getGenericParameterType()); } else { return JSON.parseObject(sb.toString(), parameter.getParameterType()); } } } }

JSONObjectWrapper
package com.common; import com.alibaba.fastjson.JSONObject; /** * description: JSONObjectWrapper * * JSONObject实现了Map接口,所以Spring MVC的默认处理器MapMethodProcessor会先处理, * 这里封装起来避免原始类型是JSONObject的参数被MapMethodProcessor处理 * * @date: 2020-03-31 10:08 * @author: shangjie * @version: 1.0 */ public class JSONObjectWrapper { private JSONObject jsonObject; public JSONObjectWrapper(JSONObject jsonObject) { this.jsonObject = jsonObject; } public JSONObject getJSONObject() { return jsonObject; } }

Springboot配置
package com; import com.common.FastJsonArgumentResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class ApplicationConfiguration implements WebMvcConfigurer { private static final Logger logger = LoggerFactory.getLogger(ApplicationConfiguration.class); @Override public void addArgumentResolvers(List resolvers) { resolvers.add(new FastJsonArgumentResolver()); } }

使用HandlerMethodArgumentResolver解析过程分析
  1. 配置类实现WebMvcConfigurer接口的下述方法
    public void addArgumentResolvers(List resolvers)

    来进行配置
  2. spring使配置ArgumentResolvers使用的是org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter类中的getDefaultArgumentResolvers方法
    private List getDefaultArgumentResolvers() { List resolvers = new ArrayList<>(); // Annotation-based argument resolution resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false)); resolvers.add(new RequestParamMapMethodArgumentResolver()); resolvers.add(new PathVariableMethodArgumentResolver()); resolvers.add(new PathVariableMapMethodArgumentResolver()); resolvers.add(new MatrixVariableMethodArgumentResolver()); resolvers.add(new MatrixVariableMapMethodArgumentResolver()); resolvers.add(new ServletModelAttributeMethodProcessor(false)); resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice)); resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice)); resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory())); resolvers.add(new RequestHeaderMapMethodArgumentResolver()); resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new SessionAttributeMethodArgumentResolver()); resolvers.add(new RequestAttributeMethodArgumentResolver()); // Type-based argument resolution resolvers.add(new ServletRequestMethodArgumentResolver()); resolvers.add(new ServletResponseMethodArgumentResolver()); resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice)); resolvers.add(new RedirectAttributesMethodArgumentResolver()); resolvers.add(new ModelMethodProcessor()); resolvers.add(new MapMethodProcessor()); resolvers.add(new ErrorsMethodArgumentResolver()); resolvers.add(new SessionStatusMethodArgumentResolver()); resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); // Custom arguments if (getCustomArgumentResolvers() != null) { resolvers.addAll(getCustomArgumentResolvers()); } // Catch-all resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); resolvers.add(new ServletModelAttributeMethodProcessor(true)); return resolvers; }

  3. spring处理http请求过程中在org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues方法里解析request中传入的参数
    private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {MethodParameter[] parameters = getMethodParameters(); Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); // 这里解析参数 args[i] = resolveProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } if (this.argumentResolvers.supportsParameter(parameter)) { try { args[i] = this.argumentResolvers.resolveArgument( parameter, mavContainer, request, this.dataBinderFactory); continue; } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex); } throw ex; } } if (args[i] == null) { throw new IllegalStateException("Could not resolve method parameter at index " + parameter.getParameterIndex() + " in " + parameter.getExecutable().toGenericString() + ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i)); } } return args; }

  4. org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#resolveArgument方法里选定了resolver,并进行解析
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {// 这里选择resolver HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); if (resolver == null) { throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]"); } // 这里解析 return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); }

  5. org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#getArgumentResolver方法选择resolver。这里也解释了定义JSONObjectWrapper类的意义,由于JSONObject实现了Map接口,而在getDefaultArgumentResolvers方法中注册的解析Map的resolverMapMethodProcessor在自定义resolver之前。所以将JSONObject封装,避免原始类型是JSONObject的参数被MapMethodProcessor处理被MapMethodProcessor解析
    private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) { HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter); if (result == null) { for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) { if (logger.isTraceEnabled()) { logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" + parameter.getGenericParameterType() + "]"); } // 这里从注册的resolver中顺序选择支持解析对应parameter的resolver if (methodArgumentResolver.supportsParameter(parameter)) { result = methodArgumentResolver; this.argumentResolverCache.put(parameter, result); break; } } } return result; }

参考
  • spring mvc3 + fastjson

    推荐阅读