您的位置:首页 > 编程语言 > Java开发

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

2016-02-18 08:55 555 查看
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) {
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对象上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: