目录
(四)附加:解析普通参数resolveCommonArgument
(一) 首先设置几个参数的值,便于后面的理解
@RequestMapping("/updateBook")
public String updateBook(
@RequestParam(value="author")String author,
Map<String, Object> model,
HttpServletRequest request,
@ModelAttribute("haha")Book book)
{
return "liangwangshou";
}
(二)确定方法运行时使用的每一个参数的值
解析参数:Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel)
先让大家浏览一下大概的层次结构,根据这个结构来更好学习下面的方法
标了注解:
保存时哪个注解的详细信息;
如果参数有ModelAttribute注解;
拿到ModelAttribute注解的值让attrName保存
attrName="haha"
没标注解:
1)、先看是否普通参数(是否原生API)
再看是否Model或者Map,如果是就传入隐含模型;
2)、自定义类型的参数没有ModelAttribute 注解
1)、先看是否原生API
2)、再看是否Model或者Map
3)、再看是否是其他类型的比如SessionStatus、HttpEntity、Errors
4)、再看是否简单类型的属性;比如是否Integer,String,基本类型
如果是paramName=“”
5)、attrName="";
如果是自定义类型对象,最终会产生两个效果;
1)、如果这个参数标注了ModelAttribute注解就给attrName赋值为这个注解的value值
2)、如果这个参数没有标注ModelAttribute注解就给attrName赋值"";
这个方法很长很长,但是就大致分为三部分并不难(每一部分我会用红色标出便于观察),我会尽量说的明白,后面还会有总结提供理解。
private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
Class<?>[] paramTypes = handlerMethod.getParameterTypes();
//创建了一个和参数个数一样多的数组,会用来保存每一个参数的值
Object[] args = new Object[paramTypes.length];
for (int i = 0; i < args.length; i++) {
MethodParameter methodParam = new MethodParameter(handlerMethod, i);
methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
String paramName = null;
String headerName = null;
boolean requestBodyFound = false;
String cookieName = null;
String pathVarName = null;
String attrName = null;
boolean required = false;
String defaultValue = null;
boolean validate = false;
Object[] validationHints = null;
int annotationsFound = 0;
Annotation[] paramAnns = methodParam.getParameterAnnotations();
//第一部分:找到目标方法这个参数的所有注解,如果有注解就解析并保存注解的信息;并且注解的数量annotationsFound ++
for (Annotation paramAnn : paramAnns) {
if (RequestParam.class.isInstance(paramAnn)) {//判断参数是否带@RequestParam注解
RequestParam requestParam = (RequestParam) paramAnn;
paramName = requestParam.value();
required = requestParam.required();
defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
annotationsFound++;
}
else if (RequestHeader.class.isInstance(paramAnn)) {//判断参数是否带@RequestHeader注解
RequestHeader requestHeader = (RequestHeader) paramAnn;
headerName = requestHeader.value();
required = requestHeader.required();
defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
annotationsFound++;
}
else if (RequestBody.class.isInstance(paramAnn)) {//判断参数是否带@RequestBody注解
requestBodyFound = true;
annotationsFound++;
}
else if (CookieValue.class.isInstance(paramAnn)) {//判断参数是否带@CookieValue注解
CookieValue cookieValue = (CookieValue) paramAnn;
cookieName = cookieValue.value();
required = cookieValue.required();
defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
annotationsFound++;
}
else if (PathVariable.class.isInstance(paramAnn)) {//判断参数是否带@PathVariable注解
PathVariable pathVar = (PathVariable) paramAnn;
pathVarName = pathVar.value();
annotationsFound++;
}
else if (ModelAttribute.class.isInstance(paramAnn)) {//判断参数是否带@ModelAttribute注解
ModelAttribute attr = (ModelAttribute) paramAnn;
attrName = attr.value();
annotationsFound++;
}
else if (Value.class.isInstance(paramAnn)) {//判断参数是否带@Value注解
defaultValue = ((Value) paramAnn).value();
}
else if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
validate = true;
Object value = AnnotationUtils.getValue(paramAnn);
validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value});
}
}
if (annotationsFound > 1) {//判断注解的数量是否大于1,如果大于1说明该参数有两个注解,则会抛出错误
throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +
"do not specify more than one such annotation on the same parameter: " + handlerMethod);
}
// 第二部分:没有找到注解的情况;
if (annotationsFound == 0) {
//解析普通参数 会进入resolveStandardArgument(解析标准参数,后面会有补充)
Object argValue = resolveCommonArgument(methodParam, webRequest);
if (argValue != WebArgumentResolver.UNRESOLVED) {
args[i] = argValue;
}
else if (defaultValue != null) {
args[i] = resolveDefaultValue(defaultValue);
}
else {
Class<?> paramType = methodParam.getParameterType();
//判断是否是Model或者是Map旗下的,如果是将之前创建的隐含模型直接赋值给这个参数
if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {
if (!paramType.isAssignableFrom(implicitModel.getClass())) {
throw new IllegalStateException("Argument [" + paramType.getSimpleName() + "] is of type " +
"Model or Map but is not assignable from the actual model. You may need to switch " +
"newer MVC infrastructure classes to use this argument.");
}
args[i] = implicitModel;
}
else if (SessionStatus.class.isAssignableFrom(paramType)) {是否是SessionStatus类型参数
args[i] = this.sessionStatus;
}
else if (HttpEntity.class.isAssignableFrom(paramType)) {是否是HttpEntity类型参数
args[i] = resolveHttpEntityRequest(methodParam, webRequest);
}
else if (Errors.class.isAssignableFrom(paramType)) {是否是Errors类型参数
throw new IllegalStateException("Errors/BindingResult argument declared " +
"without preceding model attribute. Check your handler method signature!");
}
else if (BeanUtils.isSimpleProperty(paramType)) {//是否是基本类型参数
paramName = "";
}
else {
attrName = "";
}
}
}
//第三部分:确定值的环节
if (paramName != null) {
args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);
}
else if (headerName != null) {
args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);
}
else if (requestBodyFound) {
args[i] = resolveRequestBody(methodParam, webRequest, handler);
}
else if (cookieName != null) {
args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);
}
else if (pathVarName != null) {
args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
}
else if (attrName != null) { //确定自定义类型参数的值;还要将请求中的每一个参数赋值给这个对象
WebDataBinder binder = resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
if (binder.getTarget() != null) {
//[将请求参数中提交的每一个属性和javaBean进行绑定]
doBind(binder, webRequest, validate, validationHints, !assignBindingResult);
}
args[i] = binder.getTarget();
if (assignBindingResult) {
args[i + 1] = binder.getBindingResult();
i++;
}
加入到隐含模型中
implicitModel.putAll(binder.getBindingResult().getModel());
}
}
return args;
}
SpringMVC确定POJO值的三步;
1、如果隐含模型中有这个key(标了ModelAttribute注解就是注解指定的value,没标就是参数类型的首字母小写)指定的值;
如果有将这个值赋值给bindObject;
2、如果是SessionAttributes标注的属性,就从session中拿;
3、如果都不是就利用反射创建对象;
private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception {
// Bind request parameter onto object...
String name = attrName;
if ("".equals(name)) {
//如果attrName是空串;就将参数类型的首字母小写作为值
//跟参数名无关 例如Book book123456,它的值还是book
name = Conventions.getVariableNameForParameter(methodParam);
}
Class<?> paramType = methodParam.getParameterType();
Object bindObject;
//确定目标对象的值
if (implicitModel.containsKey(name)) {
bindObject = implicitModel.get(name);
}
else if (this.methodResolver.isSessionAttribute(name, paramType)) {
//如果是SessionAttributes标注的属性,就从session中拿
bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);
if (bindObject == null) {
raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session");
}
}
else {//如果都不是就利用反射创建对象
bindObject = BeanUtils.instantiateClass(paramType);
}
WebDataBinder binder = createBinder(webRequest, bindObject, name);
initBinder(handler, name, binder, webRequest);
return binder;
(三)目标方法确定参数总结:
确定方法每个参数的值; 1.标注解:保存注解的信息;最终得到这个注解应该对应解析的值; 2.没标注解: 1.看是否是原生API; 2.看是否是Model或者是Map, SessionStatus、 HttpEntity、 Errors... 3.看是否是简单类型; paramName="" 4.给attrName赋值; attrName (参数标了@ModelAttribte(")就是指定的,没标就是"") 1. attrName使用参数的类型首字母小写;或者使用之前@ModelAttributet(")的值 2.先看隐含模型中有每个这个attrName作为key对应的值;如果有就从隐含模型中获取并赋值 3.看是否是@SessionAttributes(value="haha");标注的属性,如果是从session中拿; 4.不是@SessionAttributes标注的,利用反射创建一个对象; 5.不是@SessionAttributes标注的,利用反射创建一个对象;
(四)附加:解析普通参数resolveCommonArgument)
即确定当前的参数是否是原生API;
@Override
protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
if (ServletRequest.class.isAssignableFrom(parameterType) ||
MultipartRequest.class.isAssignableFrom(parameterType)) {
Object nativeRequest = webRequest.getNativeRequest(parameterType);
if (nativeRequest == null) {
throw new IllegalStateException(
"Current request is not of type [" + parameterType.getName() + "]: " + request);
}
return nativeRequest;
}
else if (ServletResponse.class.isAssignableFrom(parameterType)) {
this.responseArgumentUsed = true;
Object nativeResponse = webRequest.getNativeResponse(parameterType);
if (nativeResponse == null) {
throw new IllegalStateException(
"Current response is not of type [" + parameterType.getName() + "]: " + response);
}
return nativeResponse;
}
else if (HttpSession.class.isAssignableFrom(parameterType)) {
return request.getSession();
}
else if (Principal.class.isAssignableFrom(parameterType)) {
return request.getUserPrincipal();
}
else if (Locale.class.equals(parameterType)) {
return RequestContextUtils.getLocale(request);
}
else if (InputStream.class.isAssignableFrom(parameterType)) {
return request.getInputStream();
}
else if (Reader.class.isAssignableFrom(parameterType)) {
return request.getReader();
}
else if (OutputStream.class.isAssignableFrom(parameterType)) {
this.responseArgumentUsed = true;
return response.getOutputStream();
}
else if (Writer.class.isAssignableFrom(parameterType)) {
this.responseArgumentUsed = true;
return response.getWriter();
}
return super.resolveStandardArgument(parameterType, webRequest);
}