@RequestBody注解可以用于POST请求接收请求体中的参数,使用方式如下:- @Controller
- public class IndexController {
-
- @PostMapping(value = "/submit", produces = MediaType.APPLICATION_JSON_VALUE)
- public void submit(@RequestBody UserInfo userInfo) {
- System.out.println(userInfo.toString());
- }
- }
复制代码 那么是如何从请求中解析数据设置到对应的参数中呢,接下来就从源码的角度一探究竟。
DispatcherServlet是Spring MVC的核心,它对请求进行调度,收到请求后会进入DispatcherServlet的doDispatch方法中:
- 调用getHandler方法获取请求对应的Handler处理器;
- 根据handler获取对应的适配器,这里用到了适配器模式;
- 调用适配器的handle方法处理请求,它会返回一个ModelAndView对象;
- public class DispatcherServlet extends FrameworkServlet {
- protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
- HttpServletRequest processedRequest = request;
- HandlerExecutionChain mappedHandler = null;
- boolean multipartRequestParsed = false;
- WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
- try {
- ModelAndView mv = null;
- Exception dispatchException = null;
- try {
- // 检查是否有Multipart
- processedRequest = checkMultipart(request);
- multipartRequestParsed = (processedRequest != request);
- // 根据请求获取对应的处理器
- mappedHandler = getHandler(processedRequest);
- if (mappedHandler == null) {
- noHandlerFound(processedRequest, response);
- return;
- }
- // 根据handler获取对应的适配器
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
- // ...
- // 处理请求
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- // ...
- }
- catch (Exception ex) {
- dispatchException = ex;
- }
- catch (Throwable err) {
- dispatchException = new NestedServletException("Handler dispatch failed", err);
- }
- processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
- }
- // ...
- }
- }
复制代码 通过POSTMAN模拟请求,在代码中打断点可以看到HandlerAdapter的类型为对RequestMappingHandlerAdapter:

handle方法在其父类AbstractHandlerMethodAdapter中实现,在它的handle方法中,又调用了handleInternal方法处理请求,handleInternal是一个抽象方法,由具体的子类实现:- public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
- @Override
- @Nullable
- public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- // 处理请求
- return handleInternal(request, response, (HandlerMethod) handler);
- }
- @Nullable
- protected abstract ModelAndView handleInternal(HttpServletRequest request,
- HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
- }
复制代码 所以回到RequestMappingHandlerAdapter的handleInternal方法,里面调用了invokeHandlerMethod方法进行处理:
- 创建ServletInvocableHandlerMethod;
- 调用invokeAndHandle方法继续请求处理;
- 调用getModelAndView方法返回ModelAndView;
- public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
- implements BeanFactoryAware, InitializingBean {
- @Override
- protected ModelAndView handleInternal(HttpServletRequest request,
- HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
- ModelAndView mav;
- checkRequest(request);
- if (this.synchronizeOnSession) {
- HttpSession session = request.getSession(false);
- if (session != null) {
- Object mutex = WebUtils.getSessionMutex(session);
- synchronized (mutex) {
- // 执行请求
- mav = invokeHandlerMethod(request, response, handlerMethod);
- }
- }
- else {
- // 执行请求
- mav = invokeHandlerMethod(request, response, handlerMethod);
- }
- }
- else {
- // 执行请求
- mav = invokeHandlerMethod(request, response, handlerMethod);
- }
- // ...
- return mav;
- }
- @Nullable
- protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
- HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
- ServletWebRequest webRequest = new ServletWebRequest(request, response);
- try {
- // ...
- // 创建ServletInvocableHandlerMethod
- ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
- // 调用invokeAndHandle方法处理请求
- invocableMethod.invokeAndHandle(webRequest, mavContainer);
- if (asyncManager.isConcurrentHandlingStarted()) {
- return null;
- }
- // 返回ModelAndView
- return getModelAndView(mavContainer, modelFactory, webRequest);
- }
- finally {
- webRequest.requestCompleted();
- }
- }
- }
复制代码 ServletInvocableHandlerMethod的invokeAndHandle中调用了invokeForRequest方法执行请求,它的实现在其父类InvocableHandlerMethod中:- public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
- public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
- Object... providedArgs) throws Exception {
- // 执行请求
- Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
- setResponseStatus(webRequest);
- // ...
- }
- }
复制代码 invokeForRequest中又调用了getMethodArgumentValues方法获取请求中的参数,处理逻辑如下:
- 调用getMethodParameters获取方法中的参数,也就是我们的请求处理器方法中的所有参数,上面看到submit只接收了一个UserInfo类型的参数,这里可以从断点中看到parameters中只有一个元素,类型为UserInfo:

- 对获取到方法中的所有参数进行遍历,通过处理器调用resolveArgument方法解析请求中的数据,解析每一个参数对应的值;
- public class InvocableHandlerMethod extends HandlerMethod {
- @Nullable
- public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
- Object... providedArgs) throws Exception {
- // 获取请求中的参数
- Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
- if (logger.isTraceEnabled()) {
- logger.trace("Arguments: " + Arrays.toString(args));
- }
- return doInvoke(args);
- }
-
- protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
- Object... providedArgs) throws Exception {
- // 获取方法的所有参数
- MethodParameter[] parameters = getMethodParameters();
- if (ObjectUtils.isEmpty(parameters)) {
- return EMPTY_ARGS;
- }
- Object[] args = new Object[parameters.length];
- // 对方法中的所有参数进行遍历
- for (int i = 0; i < parameters.length; i++) {
- MethodParameter parameter = parameters[i];
- parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
- // ...
- try {
- // 调用resolveArgument从请求中解析对应的数据
- args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
- }
- // ...
- }
- return args;
- }
- }
复制代码 resolveArgument方法在HandlerMethodArgumentResolverComposite中实现:
- 调用getArgumentResolver方法获取对应的参数处理器resolver;
- 调用resolver的resolveArgument方法进行参数解析;
- public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
- @Override
- @Nullable
- public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
- NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
- // 获取对应的参数处理器
- HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
- if (resolver == null) {
- throw new IllegalArgumentException("Unsupported parameter type [" +
- parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
- }
- // 解析参数
- return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
- }
- }
复制代码 从断点中可以看到此时的resolver是RequestResponseBodyMethodProcessor类型的:

进入到RequestResponseBodyMethodProcessor的resolveArgument方法中,它又调用了readWithMessageConverters方法解析参数,最终会进入到
AbstractMessageConverterMethodArgumentResolve中的readWithMessageConverters方法:- public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
- @Override
- public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
- NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
- parameter = parameter.nestedIfOptional();
- // 通过转换器进行参数解析
- Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
- String name = Conventions.getVariableNameForParameter(parameter);
- // ...
- return adaptArgumentIfNecessary(arg, parameter);
- }
- @Override
- protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
- Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
- HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
- Assert.state(servletRequest != null, "No HttpServletRequest");
- ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
- // 调用AbstractMessageConverterMethodArgumentResolver中readWithMessageConverters方法读取参数
- Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
- if (arg == null && checkRequired(parameter)) {
- throw new HttpMessageNotReadableException("Required request body is missing: " +
- parameter.getExecutable().toGenericString(), inputMessage);
- }
- return arg;
- }
- }
复制代码 readWithMessageConverters方法处理逻辑如下:
- 遍历所有HTTP消息转换器,判断是否支持解析当前的请求参数类型;
- 如果转换器支持解析当前的参数类型并且有消息体内容,调用转换器的read方法进行解析;
- public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
- @Nullable
- protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
- Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
- // ...
- try {
- message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
- // 遍历所有的消息转换器
- for (HttpMessageConverter<?> converter : this.messageConverters) {
- Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
- GenericHttpMessageConverter<?> genericConverter =
- (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
- // 判断是否支持当前参数类型的读取
- if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
- (targetClass != null && converter.canRead(targetClass, contentType))) {
- // 如果有消息体
- if (message.hasBody()) {
- HttpInputMessage msgToUse =
- getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
- // 调用read方法进行读取
- body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
- ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
- body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
- }
- else {
- body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
- }
- break;
- }
- }
- }
- catch (IOException ex) {
- throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
- }
- // ...
- return body;
- }
- }
复制代码 这里列举一些消息转换器的类型:

对于application/json;charset=UTF-8类型会进入到MappingJackson2HttpMessageConverter,read方法在其父类AbstractJackson2HttpMessageConverter,处理逻辑如下:
- 获取参数的Class类型,从断点中可以看出是[class com.example.demo.model.UserInfo];

- 调用readJavaType方法解析参数
(1)获取ContentType,前面可以看到请求接收的类型为application/json;
(2)获取字符集,这里的字符集为UTF-8;
(3)创建ObjectMapper对象,并从请求体中读取JSON数据,转为JAVA对象;
- public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object> {
- @Override
- public Object read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
- throws IOException, HttpMessageNotReadableException {
- // 获取参数的Class类型
- JavaType javaType = getJavaType(type, contextClass);
- // 解析参数
- return readJavaType(javaType, inputMessage);
- }
- private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException {
- // 获取ContentType
- MediaType contentType = inputMessage.getHeaders().getContentType();
- // 获取字符集
- Charset charset = getCharset(contentType);
- ObjectMapper objectMapper = selectObjectMapper(javaType.getRawClass(), contentType);
- Assert.state(objectMapper != null, "No ObjectMapper for " + javaType);
- boolean isUnicode = ENCODINGS.containsKey(charset.name());
- try {
- // ...
- if (isUnicode) {
- // 获取HTTP请求体中的JSON数据,转为JAVA对象
- return objectMapper.readValue(inputMessage.getBody(), javaType);
- }
- else {
- Reader reader = new InputStreamReader(inputMessage.getBody(), charset);
- return objectMapper.readValue(reader, javaType);
- }
- }
- // ....
- }
- }
复制代码 到这里已经成功从HTTP请求体中的JSON数据,并转为JAVA对象,完成了参数的设置。
Spring版本:5.3.4
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |