【spring-mvc】最常用的参数解析讲解

spring-mvc为我们提供了20多种默认的参数解析器。但是我们最常用的还是不加任何注解,直接得到我们的对象的一张参数解析方式。如下方法中的registerUser参数,spring-mvc是如何为我们创建这个有属性的对象。

/**
     * 注册
     *
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public Result register(@Valid RegisterUser registerUser,HttpServletRequest request, HttpServletResponse response) {
        if (!RegularUtils.isPhone(registerUser.getUsername()) && !RegularUtils.isEmail(registerUser.getUsername())) {
            throw new BizException("请输入有效的用户名或者邮箱");
        }
        if (registerService.findByName(registerUser.getUsername()) > 0) {
            throw new BizException("用户名已经被注册");
        }
        if (!StringUtils.equals(registerUser.getPassword(), registerUser.getConfirmPassword())) {
            throw new BizException("输入的密码不一致");
        }
        Result result = new Result();
        //第二次加密
        boolean flag = registerService.saveRegisterUser(registerUser);
        result.setSuccess(flag);
        if (flag) {
            //模拟用户登陆
            try {
                UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                        registerUser.getUsername(), registerUser.getPassword());
                authRequest.setDetails(userDetailsService);
                Authentication authentication = authenticationManager.authenticate(authRequest);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                //context最终会存储在session中
                request.getSession().setAttribute("SPRING_SECURITY_CONTEXT",SecurityContextHolder.getContext());
            } catch (AuthenticationException e) {
                result.setSuccess(false);
                result.setMessage("注册失败");
            }
        }
        return result;
    }

直接进入参数解析处,其他的转发可以看我其他篇章的讲解。
RequestMappingHandlerAdapter中有个HandlerMethodArgumentResolverComposite参数复合类。

/**
     * Find a registered {@link HandlerMethodArgumentResolver} that supports the given method parameter.
     */
    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() + "]");
                }
                if (methodArgumentResolver.supportsParameter(parameter)) {
                    result = methodArgumentResolver;
                    this.argumentResolverCache.put(parameter, result);
                    break;
                }
            }
        }
        return result;
    }

spring用到了大量的cache缓存,提高效率。暂时不讲解,主要看methodArgumentResolver.supportsParameter(parameter),此处就是遍历系统提供的参数解析器,当遍历到ServletModelAttributeMethodProcessor时,

@Override
    public boolean supportsParameter(MethodParameter parameter) {
        if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
            return true;
        }
        else if (this.annotationNotRequired) {
            return !BeanUtils.isSimpleProperty(parameter.getParameterType());
        }
        else {
            return false;
        }
    }

this.annotationNotRequired会返回true,因为我们并未提供注解,并且该参数不是简单类型,所以此方法会返回true,即RequestMappingHandlerAdapter会将此参数交给ServletModelAttributeMethodProcessor来解析,如下是解析过程:

@Override
    public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        String name = ModelFactory.getNameForParameter(parameter);
        Object attribute = (mavContainer.containsAttribute(name) ?
                mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, webRequest));

        WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
        if (binder.getTarget() != null) {
            bindRequestParameters(binder, webRequest);
            validateIfApplicable(binder, parameter);
            if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                throw new BindException(binder.getBindingResult());
            }
        }

        // Add resolved attribute and BindingResult at the end of the model
        Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
        mavContainer.removeAttributes(bindingResultModel);
        mavContainer.addAllAttributes(bindingResultModel);

        return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
    }

其中WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);是创建一个绑定工厂,其中会含有一个validator验证器等,

protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
        ServletRequest servletRequest = (ServletRequest)request.getNativeRequest(ServletRequest.class);
        ServletRequestDataBinder servletBinder = (ServletRequestDataBinder)binder;
        servletBinder.bind(servletRequest);
    }
//绑定过程
public void bind(ServletRequest request) {
    //此处是利用Web
    MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
    MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
    if (multipartRequest != null) {
        bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
    }
    addBindValues(mpvs, request);
    doBind(mpvs);
}
//获取参数的过程。
public ServletRequestParameterPropertyValues(ServletRequest request, String prefix, String prefixSeparator) {
    super(WebUtils.getParametersStartingWith(
            request, (prefix != null ? prefix + prefixSeparator : null)));
}

public MutablePropertyValues(Map<?, ?> original) {
    if(original != null) {
        this.propertyValueList = new ArrayList(original.size());
        Iterator var2 = original.entrySet().iterator();

        while(var2.hasNext()) {
            Entry entry = (Entry)var2.next();
            this.propertyValueList.add(new PropertyValue(entry.getKey().toString(), entry.getValue()));
        }
    } else {
        this.propertyValueList = new ArrayList(0);
    }
}

获取参数的方法WebUtils.getParametersStartingWith(request, (prefix != null ? prefix + prefixSeparator : null))

回归上述代码,就是MutablePropertyValues mpvs中的mpvs会通过一系列构造函数得到一个含有属性和名称的properties.

protected void doBind(MutablePropertyValues mpvs) {
        checkAllowedFields(mpvs);
        checkRequiredFields(mpvs);
        applyPropertyValues(mpvs);
    }

applyPropertyValues(mpvs)就是将参数绑定到target对象上。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑起来贼好看

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值