【spring-mvc】最常用的参数解析讲解
2016-02-18 08:55
555 查看
spring-mvc为我们提供了20多种默认的参数解析器。但是我们最常用的还是不加任何注解,直接得到我们的对象的一张参数解析方式。如下方法中的registerUser参数,spring-mvc是如何为我们创建这个有属性的对象。
直接进入参数解析处,其他的转发可以看我其他篇章的讲解。
RequestMappingHandlerAdapter中有个HandlerMethodArgumentResolverComposite参数复合类。
spring用到了大量的cache缓存,提高效率。暂时不讲解,主要看
this.annotationNotRequired会返回true,因为我们并未提供注解,并且该参数不是简单类型,所以此方法会返回true,即RequestMappingHandlerAdapter会将此参数交给
其中
获取参数的方法
回归上述代码,就是
applyPropertyValues(mpvs)就是将参数绑定到target对象上。
/** * 注册 * * @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) { resu 4000 lt.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对象上。
相关文章推荐
- Eclipse右击工程菜单中没有Android Tools选项
- Java中的数组基础知识学习教程
- java中字符串转换为日期并且格式化
- The Java™ Tutorials — Concurrency :Guarded Blocks 保护块
- myeclipse设置凝视
- java static关键字
- Java中带条件的查询
- Java中字符串相等与大小比较
- DBManager类(java jdbc数据库连接及操作)
- Atitit swt 4.3 4.4 4.5 新特性java attilax总结
- Atitit swt 4.3 4.4 4.5 新特性java attilax总结
- Atitit swt 4.3 4.4 4.5 新特性java attilax总结
- java并发编程——线程异常处理\资源共享的问题\ThreadLocal
- sublime 编译java
- Java内部类
- java.lang.NullPointerException: Expected timestamp
- Mybatis Could not find result map java.lang.Intege
- java 通过Spark实现单词计数的功能
- SpringMVC 使用Fastjson代替Jackson
- 在web应用中获取spring的context,并打印出context中所有bean的id