【springboot】Servlet API参数解析(一)及Model、Map类型源码分析(二)及√自定义参数(POJO类型)(三)

这里的自定义参数解析指的是POJO类型的封装过程。

首页写一表单:

且声明两个POJO类(目标参数):

且Pet和Person是级联关系。

(@Data是lombok提供的补充POJO类getter、setter、toString方法实现的注释)

POJO类的封装过程是由ServletModelAttributeMethodProcessor执行的。

只有第二个ServletModelAttributeMethodProcessor才是符合的

两者不一样,后者不需要@ModelAttribute注释:stepInto这个supportsParameter方法查看,

要么1有这个annoation(@ModelAttribute)要么2不需要注释(annotationNotRequired)而且不是简单参数(isSimpleProperty)。

那么问题就来了,怎么判断是否为简单参数?通过isSimpleProperty方法判断:

首先参数类型type非null。(type就是前文的parameter.getParameterType()得到的值)其次还需要①type满足isSimpleValueType方法or②type是数组&type的component类型也满足isSimpleValueType方法。其实应该加上():

先evaluate各部分的值: 

可见返回false。

也可以进入isSimpleValueType方法,看那些类型是符合SimpleValue要求的:

因此可以知道supportsParameter方法返回值为true:

(一)接着解析参数,进入解析参数的核心方法resolveArgument:

ModelAttributeMethodProcessor.resolveArugument部分方法1-1-创建ModelAttribute对象ann(null)

先判断是否有加ModelAttribute注解,然后得到一个新的ModelAttribute对象。这里我们明显是没有加的,所以ann对象为null。(但是如果有注解的话,mavContainer就会将POJO参数的名字跟这个modelAttribute对象进行绑定。)后面进行//create attribute instance(属性实例的创建):

ModelAttributeMethodProcessor.resolveArugument部分方法1-2-得到attribute对象(createAttribute创建POJO参数)

进入createAttribute方法:

ModelAttributeMethodProcessor.resolveArugument部分方法1-2-3-createAttribute方法
ModelAttributeMethodProcessor.resolveArugument部分方法1-2-3-4-createAttribute方法

可见内层的createAttribute方法就是根据parameter的信息——>>POJO类的构造器clazz(attributeName是'person') 。

然后建立了attribute对象。返回的attribute为:

attribute是Person类型的,但是value全为null,还未给各个参数绑定(binding)对应的值。 

 (oops...突然发现忘记在Person类中级联添加Pet为级联对象属性了)

(二)此时又不得不提到我们的原生请求(携带所有请求信息,待处理)了,依旧是在ModelAttributeMethodProcessor类中,进入binding(值)阶段:

(注:binding阶段不仅1bind绑定还会进行2validate验证)

ModelAttributeMethodProcessor.resolveArugument部分方法2-binding绑定值阶段

最核心的部分就是createBinder方法:

查看binder是何方神圣?

WebDataBinder(Web数据绑定器)将请求参数的值绑定到指定的JavaBean(POJO类对象)中。

具体是如何实现的呢?binder

①target包含了我们刚刚创建的空atrribute(请求参数)的信息,而且binder含有一个convertService(数据转换”服务)

②可以利用其中的cjinonverters将请求数据转换成指定的数据类型,再次封装到JavaBean对象中:

 然后经过以下方法后binder中原值为null的target(目标注入值对象)——Person已经被赋值了:

注:此处省略bindRequestParameters方法的解析(可能后面会填坑)。

这个方法主要就是如何给请求参数绑定值的各种转换细节:

【附】springMVC做了很多准备工作:

比如自动配置中的converters。 下面的ConfigurableWebBindingInitializer就是一个例子:

最后,附上resolveArgument解析参数的核心方法完整源码:

@Nullable
    public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
        Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
        String name = ModelFactory.getNameForParameter(parameter);
        ModelAttribute ann = (ModelAttribute)parameter.getParameterAnnotation(ModelAttribute.class);
        if (ann != null) {
            mavContainer.setBinding(name, ann.binding());
        }

        Object attribute = null;
        BindingResult bindingResult = null;
        if (mavContainer.containsAttribute(name)) {
            attribute = mavContainer.getModel().get(name);
        } else {
            try {
                attribute = this.createAttribute(name, parameter, binderFactory, webRequest);
            } catch (BindException var10) {
                if (this.isBindExceptionRequired(parameter)) {
                    throw var10;
                }

                if (parameter.getParameterType() == Optional.class) {
                    attribute = Optional.empty();
                } else {
                    attribute = var10.getTarget();
                }

                bindingResult = var10.getBindingResult();
            }
        }

        if (bindingResult == null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
            if (binder.getTarget() != null) {
                if (!mavContainer.isBindingDisabled(name)) {
                    this.bindRequestParameters(binder, webRequest);
                }

                this.validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
                    throw new BindException(binder.getBindingResult());
                }
            }

            if (!parameter.getParameterType().isInstance(attribute)) {
                attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
            }

            bindingResult = binder.getBindingResult();
        }

        Map<String, Object> bindingResultModel = bindingResult.getModel();
        mavContainer.removeAttributes(bindingResultModel);
        mavContainer.addAllAttributes(bindingResultModel);
        return attribute;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值