美文网首页
SpringMVC-请求参数绑定原理

SpringMVC-请求参数绑定原理

作者: CalmHeart | 来源:发表于2022-03-16 22:05 被阅读0次
  • 控制层框架历史:

Servlet->Structs1.0->Structs2.0->SpringMVC->SpringBoot(嵌入式)

  • 其实控制层框架包含两个层面的绑定:路由地址的绑定(涉及控制器及具体路由方法绑定)、请求参数的绑定,本文讲的是后者 后续有时间会同步前者
  • 1. 你知道的参数绑定注解有哪些?

所属jar:org.springframework:spring-web:5.2.12.RELEASE


org.springframework:spring-web:5.2.12.RELEASE

所属package:package org.springframework.web.bind.annotation


package org.springframework.web.bind.annotation

标注有@Target(ElementType.PARAMETER)注解的均属于参数绑定注解如下:

@CookieValue(绑定客户端的cookie属性)
@MatrixVariable(是对@PathVariable的增强)
@ModelAttribute
@PathVariable(路径参数绑定)
@RequestAttribute(服务端自身参数绑定)
@RequestBody(请求体json或者xml参数绑定)
@RequestHeader(请求头参数绑定)
@RequestParam(param参数绑定)
@RequestPart(文件上传参数绑定)
@SessionAttribute(session属性绑定)

@SessionAttributes(session属性绑定) 作用域类上

  • 2. 简单介绍一下上面注解的使用方法 参考:ParamBindController.java

涉及的相关代码如下:

public class RequestAttributeInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        request.setAttribute("username", "小喇叭");
        //设置session属性
        HttpSession session = request.getSession();
        session.setAttribute("age", 100);
        return true;
    }
}

/**
 * Spring 3.2就已经支持@MatrixVariable特性,但直至现在其依然为默认禁用的状态
 *
 * @author lvsheng
 * @version 1.0.0
 * @date 2022/03/08 13:14
 * @see WebMvcConfigurer
 */
@Configuration
public class MatrixVariableConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        WebMvcConfigurer.super.addInterceptors(registry);
        registry.addInterceptor(new RequestAttributeInterceptor()).addPathPatterns("/**/request-attribute", "/**/session-attribute");
    }
}

package com.oceanus.bind.sharing;

import cn.hutool.core.util.StrUtil;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.MatrixVariable;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.multipart.MultipartFile;

@Slf4j
@Controller
@SessionAttributes(types = {UserDto.class}, value = "userDto")
@RequestMapping("/param")
public class ParamBindController {

    /**
     * 响应
     */
    @Resource
    private HttpServletResponse response;

    /**
     * 请求
     */
    @Resource
    private HttpServletRequest request;

//    /**
//     * 预请求:
//     *
//     * 被@ModelAttribute注释的方法会在这个控制器每个方法执行前被执行
//     *
//     * @author lvsheng
//     * @date 2022/03/08 15:54
//     */
//    @ModelAttribute
//    public void preRequest() {
//        preRequestForRequestAttribute();
//        preRequestForSessionAttribute();
//    }


    /***
     * 预请求-cookie值
     *
     * @author lvsheng
     * @date 2022/03/08 10:56
     */
    @ResponseBody
    @GetMapping("/pre-request/cookie-value")
    public void preRequestForCookieValue() {
        Cookie cookie = new Cookie("username", "lvsheng");
        response.addCookie(cookie);
    }

    /**
     * 预请求-request-attribute请求转发
     *
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 14:32
     */
    @GetMapping("/pre-request/request-attribute")
    public String preRequestForRequestAttribute() {
        //设置服务端系统属性参数
        request.setAttribute("username", "小麻花");
        return "forward:/param/request-attribute";
    }

    /**
     * 预请求-session-attribute请求转发
     *
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 14:32
     */
    @GetMapping("/pre-request/session-attribute")
    public String preRequestForSessionAttribute() {
        //设置session属性
        HttpSession session = request.getSession();
        session.setAttribute("age", 100);
        return "forward:/param/session-attribute";
    }

    /***
     * cookie值
     * Since:
     * 3.0
     *
     * 操作步骤:
     *
     * STEP1: http://localhost:8041/param/pre-request/cookie-value
     * STEP2: http://localhost:8041/param/cookie-value
     *
     * @param username 用户名称
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 10:56
     */
    @ResponseBody
    @GetMapping("/cookie-value")
    public String cookieValue(@CookieValue(value = "username", defaultValue = "xmz") String username) {
        return "username=" + username;
    }


    /***
     * 矩阵变量-单个属性接收
     *
     * Spring 3.2就已经支持@MatrixVariable特性,但直至现在其依然为默认禁用的状态
     * 是为了增强URL请求地址的功能 需要配置removeSemicolonContent属性值为false才生效
     * com.compass.msg.web.core.config.MatrixVariableConfig#configurePathMatch(org.springframework.web.servlet.config.annotation.PathMatchConfigurer)
     *
     * 用法: ;是用来分割变量的 ,是用来分割多个值的(多个值也可以使用多个相同的变量命名)
     *
     * 测试:
     * http://localhost:8041/param/matrix-variable/attribute/username=lvsheng;age=100
     *
     * @param username 用户名
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 11:05
     */
    @ResponseBody
    @GetMapping("/matrix-variable/attribute/{variable}")
    public String matrixVariableAttribute(@MatrixVariable(value = "username", defaultValue = "xmz") String username,
            @MatrixVariable("age") Integer age) {
        return "username=" + username + ";age=" + age;
    }

    /***
     * 矩阵变量-Map接收
     *
     * 测试:
     * http://localhost:8041/param/matrix-variable/attribute/username=lvsheng;age=100
     *
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 13:46
     */
    @ResponseBody
    @GetMapping("/matrix-variable/map/{variable}")
    public String matrixVariableMap(@MatrixVariable Map<String, Object> map) {
        return "username=" + map.get("username") + ";age=" + map.get("age");
    }

    /***
     * 矩阵变量-List接收
     *
     * 测试:
     * http://localhost:8041/param/matrix-variable/list/address=上海,苏州,昆山
     * http://localhost:8041/param/matrix-variable/list/address=上海;address=苏州;address=昆山
     *
     * @param addressList 地址列表
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 13:24
     */
    @ResponseBody
    @GetMapping("/matrix-variable/list/{variable}")
    public String matrixVariableList(@MatrixVariable("address") List<String> addressList) {
        return String.join(StrUtil.COMMA, addressList);
    }

    /***
     * 矩阵变量-数组接收
     *
     * 测试:
     * http://localhost:8041/param/matrix-variable/arr/address=上海,苏州,昆山
     * http://localhost:8041/param/matrix-variable/arr/address=上海;address=苏州;address=昆山
     *
     * @param addressArr 地址数组
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 13:24
     */
    @ResponseBody
    @GetMapping("/matrix-variable/arr/{variable}")
    public String matrixVariableArr(@MatrixVariable("address") String[] addressArr) {
        return String.join(StrUtil.COMMA, addressArr);
    }

    /***
     * 矩阵变量的路径PathVariable及MatrixVariable搭配使用
     *
     * 测试:
     * http://localhost:8041/param/matrix-variable/path/lvsheng;address=上海
     *
     * @param username 用户名
     * @param address 地址
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 13:40
     */
    @ResponseBody
    @GetMapping("/matrix-variable/path/{username}")
    public String matrixVariablePath(@PathVariable("username") String username, @MatrixVariable("address") String address) {
        return "username=" + username + ";address=" + address;
    }


    /***
     * 模型属性
     * Since:
     * 2.5
     *
     * 测试:
     * http://localhost:8041/param/model-attribute?username=lvsheng&age=100&address=山海
     *
     * @param userDto 用户
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 14:00
     */
    @ResponseBody
    @GetMapping("/model-attribute")
    public String modelAttribute(@ModelAttribute UserDto userDto) {
        return "username=" + userDto.getUsername() + ";age=" + userDto.getAge() + ";address=" + userDto.getAddress();
    }


    /***
     * 路径变量
     * Since:
     * 3.0
     * 测试:
     * http://localhost:8041/param/path-variable/你好
     *
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 14:02
     */
    @ResponseBody
    @GetMapping("/path-variable/{info}")
    public String pathVariable(@PathVariable String info) {
        return info;
    }

    /***
     * 请求属性 Since: 4.3
     *
     * 接收服务端设置的属性值 并非客户端(前端传递)的属性值-@RequestParam等其他注解均是客户端参数
     *
     * 测试:
     * WAY1: http://localhost:8041/param/pre-request/request-attribute(请求转发)
     *
     * WAY2: http://localhost:8041/param/request-attribute (拦截器操作)
     *
     * WAY3: 将preRequest注释代码打开(@ModelAttribute预存值)
     *
     * @param username 用户名
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 14:04
     */
    @ResponseBody
    @GetMapping("/request-attribute")
    public String requestAttribute(@RequestAttribute(required = false) String username) {
        return "username=" + username;
    }


    /***
     *
     * 请求体
     *
     * Since:
     * 3.0
     *
     * 测试:
     *
     * curl --location --request GET 'http://localhost:8041/param/request-body' \
     * --header 'Content-Type: application/json' \
     * --header 'Cookie: username=lvsheng' \
     * --data-raw '{
     *     "username": "吕升",
     *     "age": 100,
     *     "address": "上海"
     * }'
     *
     * @param userDto 用户
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 14:50
     */
    @ResponseBody
    @GetMapping("/request-body")
    public String requestBody(@RequestBody UserDto userDto) {
        return userDto.toString();
    }

    /***
     * 请求头
     * Since:
     * 3.0
     *
     * 测试:
     *
     * curl --location --request GET 'http://localhost:8041/param/request-header' \
     * --header 'username: zhangsan' \
     * --header 'Cookie: username=lvsheng'
     *
     * @param username 用户名
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 14:52
     */
    @ResponseBody
    @GetMapping("/request-header")
    public String requestHeader(@RequestHeader String username) {
        return "username=" + username;
    }

    /***
     * 请求参数
     * Since:
     * 2.5
     *
     * 测试:
     *
     * http://localhost:8041/param/request-param?username=lvsheng
     *
     * @param username 用户名
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 14:53
     */
    @ResponseBody
    @GetMapping("/request-param")
    public String requestParam(@RequestParam String username) {
        return "username=" + username;
    }

    /***
     * 请求的一部分
     * Since:
     * 3.1
     *
     * 测试: curl --location --request GET 'http://localhost:8041/param/request-part' \ --header 'Cookie: username=lvsheng;
     * JSESSIONID=AE346BDC6BB4211C14CBF6A7F84D5B58' \ --form 'upload=@"/C:/Users/sheng.lv/AppData/Local/Postman/app-8.12.4/Squirrel-UpdateSelf.log"'
     *
     * @param multipartFile 文件
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 15:07
     */
    @ResponseBody
    @GetMapping("/request-part")
    public String requestPart(@RequestPart("upload") MultipartFile multipartFile) {
        return multipartFile.getOriginalFilename();
    }

    /***
     * 会话属性
     * Since:
     * 4.3
     *
     * 测试:
     *
     * WAY1: http://localhost:8041/param/pre-request/session-attribute(请求转发)
     *
     * WAY2: http://localhost:8041/param/session-attribute(拦截器)
     *
     * WAY3: 将preRequest注释代码打开(@ModelAttribute预存值)
     *
     * @param age 年龄
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/08 15:06
     */
    @ResponseBody
    @GetMapping("/session-attribute")
    public String sessionAttribute(@SessionAttribute Integer age) {
        return "age=" + age;
    }

    /**
     * 会话属性 需要结合@SessionAttributes注解使用 该注解是作用于类上的
     *
     * @param model 模型
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/09 09:09
     */
    @GetMapping("/session-attributes")
    public String sessionAttributes(Model model) {
        UserDto userDto = new UserDto()
                .setUsername("吕升")
                .setAge(100)
                .setAddress("上海");

        // 这步操作结合+@SessionAttributes(types = {UserDto.class}, value = "userDto")会将userDto放置到
        // HttpSession中
        model.addAttribute("userDto", userDto);
        return "forward:/param/session-attributes/get";
    }

    /**
     * 获取会话属性
     *
     * @param userDto 用户请求实体
     * @return {@link String }
     * @author lvsheng
     * @date 2022/03/09 09:09
     */
    @ResponseBody
    @GetMapping("/session-attributes/get")
    public String getSessionAttribute(@SessionAttribute UserDto userDto) {
        return userDto.toString();
    }
}

  • 拓展:


    filter>interceptor>advice>aspect>controller
完整
  • 3. 常用的参数绑定注解如下:

(1) ModelAttribute
(2) PathVariable
(3) RequestBody
(4) RequestParam

  • 4. 选取部分注解研究一下内部绑定流程:

spring-mvc工作流程

@PathVariable

@RequestBody RequestBody 绑定对象是使用setter方法还是直接属性赋值?
(jackson object-mapper setter赋值)

  • 5. 源码跟踪

  • 5.1 @PathVariable参数绑定的核心流程:

1 ) org.springframework.web.servlet.DispatcherServlet#doDispatch

//调用处理器 在这个步骤中完成参数绑定操作
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

2 ) 根据handler的参数注解定位到对应参数解析器
3 ) 调用对应参数解析器的org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver#resolveName方法
4 ) 反射调用handler(Method)的invoke方法
org.springframework.web.method.support.InvocableHandlerMethod#doInvoke

/**
     * Invoke the handler method with the given argument values.
     */
    @Nullable
    protected Object doInvoke(Object... args) throws Exception {
        ReflectionUtils.makeAccessible(getBridgedMethod());
        try {
            return getBridgedMethod().invoke(getBean(), args);
        }
        catch (IllegalArgumentException ex) {
            assertTargetBean(getBridgedMethod(), getBean(), args);
            String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
            throw new IllegalStateException(formatInvokeError(text, args), ex);
        }
        catch (InvocationTargetException ex) {
            // Unwrap for HandlerExceptionResolvers ...
            Throwable targetException = ex.getTargetException();
            if (targetException instanceof RuntimeException) {
                throw (RuntimeException) targetException;
            }
            else if (targetException instanceof Error) {
                throw (Error) targetException;
            }
            else if (targetException instanceof Exception) {
                throw (Exception) targetException;
            }
            else {
                throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
            }
        }
    }
  • 关键点:
    org.springframework.web.method.HandlerMethod#parameters 参数初始化过程:
    在实例化SourceController的时候进行参数初始化


    debug栈
  • HandlerMethodArgumentResolver 初始化的流程:
    step1:
    org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory 向org.springframework.beans.factory.support.DefaultListableBeanFactory#beanDefinitionNames中添加RequestMappingHandlerAdapter

@SpringBootApplication->@EnableAutoConfiguration->spring.factories->org.springframework.boot.autoconfigure.EnableAutoConfiguration->org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration->WebMvcAutoConfiguration$EnableWebMvcConfiguration->

step2:
org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization中实例化RequestMappingHandlerAdapter Bean并调用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#afterPropertiesSet初始化HandlerMethodArgumentResolver

  • 注入RequestMappingHandlerAdapter代码:
@Bean
        @Override
        public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
                @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
                @Qualifier("mvcConversionService") FormattingConversionService conversionService,
                @Qualifier("mvcValidator") Validator validator) {
            RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager,
                    conversionService, validator);
            adapter.setIgnoreDefaultModelOnRedirect(
                    this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
            return adapter;
        }
  • RequestMappingHandlerAdapter的afterPropertiesSet方法初始化HandlerMethodArgumentResolver对象列表
    org.springframework.beans.factory.InitializingBean
    其实是维护在HandlerMethodArgumentResolverComposite的argumentResolvers属性中
    @Override
    public void afterPropertiesSet() {
        // Do this first, it may add ResponseBody advice beans
        initControllerAdviceCache();
        if (this.argumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.initBinderArgumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.returnValueHandlers == null) {
            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
        }
    }
  • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getDefaultArgumentResolvers
/**
     * Return the list of argument resolvers to use including built-in resolvers
     * and custom resolvers provided via {@link #setCustomArgumentResolvers}.
     */
    private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);

        // 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;
    }
  • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getDefaultInitBinderArgumentResolvers
/**
     * Return the list of argument resolvers to use for {@code @InitBinder}
     * methods including built-in and custom resolvers.
     */
    private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(20);

        // 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 ExpressionValueMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new SessionAttributeMethodArgumentResolver());
        resolvers.add(new RequestAttributeMethodArgumentResolver());

        // Type-based argument resolution
        resolvers.add(new ServletRequestMethodArgumentResolver());
        resolvers.add(new ServletResponseMethodArgumentResolver());

        // Custom arguments
        if (getCustomArgumentResolvers() != null) {
            resolvers.addAll(getCustomArgumentResolvers());
        }

        // Catch-all
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));

        return resolvers;
    }
  • 5.2 @RequestBody参数绑定的核心流程:

org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor


相同映射方法名及参数名对比缓存值

同@PathVariable相比多了MessageConvert处理

  • 6. 相关:

@RequestParam同RequestAttribute区别:@RequestParam绑定的是客户端参数 @RequestAttribute绑定的是服务端参数(过滤器、拦截器、Aop等场景设置的参数)
@ModelAttribute和@RequestBody 区别

相关文章

  • SpringMVC-请求参数绑定原理

    控制层框架历史: Servlet->Structs1.0->Structs2.0->SpringMVC->Spri...

  • SpringMVC-参数绑定

    一、概要 在springmvc中,接收前端提交的数据是通过方法形参来接收的。从客户端请求的key/value数据,...

  • 5、SpringMVC-参数绑定

    一、概要 在springmvc中,接收前端提交的数据是通过方法形参来接收的。从客户端请求的key/value数据,...

  • SpringMVC-参数绑定(二)

    本篇文章主要介绍Controller方法的形参类型为:基本数据类型、Date、数组、对象、集合类的数据如何与客户端...

  • SpringMVC-参数绑定(一)

    本文主要介绍SpringMVC中@PathVariable、@RequestParam、@RequestBody、...

  • SpringMVC-参数绑定(三)

    本篇文章主要介始PropertyEditor、Formatter、Converter的用法 PropertyEdi...

  • springMVC请求参数的绑定

    第3章 请求参数的绑定 1 绑定说明 1.1 绑定的机制 我们都知道,表单中请求参数都是基于 key=value ...

  • 参数绑定

    一 参数绑定过程 从客户端请求key/value数据,经过参数绑定,将key/value数据绑定到controll...

  • Spring注解

    @ModelAttribute1.绑定请求参数到命令对象:放在功能处理方法的入参上时,用于将多个请求参数绑定到一个...

  • .netCore webApi相关

    controller: 输入参数模型绑定接口的输入参数就是通过模型绑定将 HTTP 请求中的值映射到参数中,模型绑...

网友评论

      本文标题:SpringMVC-请求参数绑定原理

      本文链接:https://www.haomeiwen.com/subject/vygnrrtx.html