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

来源:互联网 发布:知乎客厅地板还是地砖 编辑:程序博客网 时间:2024/06/06 07:09

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对象上。

0 0
原创粉丝点击