使用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解析过程分析
- 配置类实现
WebMvcConfigurer
接口的下述方法public void addArgumentResolvers(List resolvers)
来进行配置 - 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; }
- 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; }
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); }
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
推荐阅读
- =======j2ee|spring用注解实现注入的@resource,@autowired,@inject区别
- jar|springboot项目打成jar包和war包,并部署(快速打包部署)
- 数据库|效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】)...
- java人生|35K 入职华为Java开发那天,我哭了(这 5 个月做的一切都值了)
- Java毕业设计项目实战篇|Java项目:在线嘿嘿网盘系统设计和实现(java+Springboot+ssm+mysql+maven)
- 微服务|微服务系列:服务发现与注册-----Eureka(面试突击!你想了解的Eureka都在这里.持续更新中......)
- java|ApplicationListener和SpringApplicationRunListener的联系
- Spring|SpringSecurity--自定义登录页面、注销登录配置
- 性能|性能工具之 Jmeter 通过 SpringBoot 工程启动
- 代码狂魔|Spring源码分析之IOC容器初始化流程