SpringBoot Web开发(二)

1.普通参数与基本注解

  1. 注解:
  • @PathVariable(路径变量)
    @GetMapping("/car/{id}")
    public Map<String,Object> getUser(@PathVariable int id){
    
    
        return null;
    }
  • @RequestHeader(获取请求头)
  • @ModelAttribute
  • @RequestParam(获取请求参数)
	//http://127.0.0.1:8080/pet?pet_id=5&interests=football&interests=swim
    @GetMapping("/pet")
    public Map<String,Object> getPet(@RequestParam("pet_id") int id, @RequestParam("interests") List<String> list,
                                     @RequestParam Map<String,String> map){
    
    
        return null;
    }
  • @MatrixVariable(矩阵变量,SpringBoot默认禁用)
  • @CookieValue(获取cookie的值)
  • @RequestBody(获取请求体[POST])
  • @RequestAttribute(“存储在请求域中的的名字”)
  1. Servlet API
  • WebRequest
  • ServletRequest
  • MultipartRequest
  • HttpSession
  • javax.servlet.http.PushBuilder
  • Principal
  • InputStream
  • Reader
  • HttpMethod
  • Locale
  • TimeZone
  • ZoneId
  1. 复杂参数
    Map、Model(map、model里面的数据会被放在request的请求域 request.setAttribute)、Errors/BindingResult、RedirectAttributes( 重定向携带数据)、ServletResponse(response)、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder
  2. 自定义对象参数

2. 参数处理原理

 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
    
    
            try {
    
    
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
    
    
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
    
    
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
					//为当前handler找一个适配器
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
    
    
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
    
    
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    
    
                        return;
                    }
					//实际调用handler
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
    
    
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
    
    
                    dispatchException = var20;
                } catch (Throwable var21) {
    
    
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
    
    
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
    
    
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
    
    
            if (asyncManager.isConcurrentHandlingStarted()) {
    
    
                if (mappedHandler != null) {
    
    
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
    
    
                this.cleanupMultipart(processedRequest);
            }

        }
    }
 protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    
    
        if (this.handlerAdapters != null) {
    
    
            Iterator var2 = this.handlerAdapters.iterator();

            while(var2.hasNext()) {
    
    
                HandlerAdapter adapter = (HandlerAdapter)var2.next();
                if (adapter.supports(handler)) {
    
    
                    return adapter;
                }
            }
        }

        throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

在这里插入图片描述

  • HandlerMapping中找到能处理请求的Handler(Controller中的方法)
  • 为当前Handler找一个适配器(HandlerAdapter )
1.HandlerAdapter
  • 0 - 支持方法上标注@RequestMapping
  • 1 - 支持函数式编程的方法
  • 3 -
2.执行目标方法
//执行目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

//ServletInvocableHandlerMethod
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

//获取方法的参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
3. 参数解析器

确定将要执行的目标方法的每一个参数的值是什么;
SpringMVC目标方法能写多少种参数类型。取决于参数解析器种类。
在这里插入图片描述

下图为参数解析器实现的接口

在这里插入图片描述

  • 首先判断当前解析器是否支持这种参数
  • 支持就调用解析方法
4.返回值处理器

在这里插入图片描述

5. 确定目标方法每一个参数的值
//InvocableHandlerMethod类
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    
    
        MethodParameter[] parameters = this.getMethodParameters();
        if (ObjectUtils.isEmpty(parameters)) {
    
    
            return EMPTY_ARGS;
        } else {
    
    
            Object[] args = new Object[parameters.length];
			
            for(int i = 0; i < parameters.length; ++i) {
    
    
                MethodParameter parameter = parameters[i];
                parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
                args[i] = findProvidedArgument(parameter, providedArgs);
                if (args[i] == null) {
    
    
                    if (!this.resolvers.supportsParameter(parameter)) {
    
    
                        throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
                    }

                    try {
    
    
                    	//解析参数
                        args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
                    } catch (Exception var10) {
    
    
                        if (this.logger.isDebugEnabled()) {
    
    
                            String exMsg = var10.getMessage();
                            if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
    
    
                                this.logger.debug(formatArgumentError(parameter, exMsg));
                            }
                        }

                        throw var10;
                    }
                }
            }

            return args;
        }
    }
5.1 挨个判断所有参数解析器哪个支持解析这个参数
    @Nullable
    private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    
    
        HandlerMethodArgumentResolver result = (HandlerMethodArgumentResolver)this.argumentResolverCache.get(parameter);
        if (result == null) {
    
    
            Iterator var3 = this.argumentResolvers.iterator();

            while(var3.hasNext()) {
    
    
                HandlerMethodArgumentResolver resolver = (HandlerMethodArgumentResolver)var3.next();
                if (resolver.supportsParameter(parameter)) {
    
    
                    result = resolver;
                    this.argumentResolverCache.put(parameter, resolver);
                    break;
                }
            }
        }

        return result;
    }
}
5.2 解析这个参数的对象

调用各自 HandlerMethodArgumentResolver 的 resolveArgument 方法即可

5.3 自定义类型参数 封装POJO

ServletModelAttributeMethodProcessor 这个参数处理器支持

// 是否为简单类型。
public static boolean isSimpleValueType(Class<?> type) {
    
    
		return (Void.class != type && void.class != type &&
				(ClassUtils.isPrimitiveOrWrapper(type) ||
				Enum.class.isAssignableFrom(type) ||
				CharSequence.class.isAssignableFrom(type) ||
				Number.class.isAssignableFrom(type) ||
				Date.class.isAssignableFrom(type) ||
				Temporal.class.isAssignableFrom(type) ||
				URI.class == type ||
				URL.class == type ||
				Locale.class == type ||
				Class.class == type));
	}
@Override
	@Nullable
	public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    
    

		Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
		Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");

		String name = ModelFactory.getNameForParameter(parameter);
		ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
		if (ann != null) {
    
    
			mavContainer.setBinding(name, ann.binding());
		}

		Object attribute = null;
		BindingResult bindingResult = null;

		if (mavContainer.containsAttribute(name)) {
    
    
			attribute = mavContainer.getModel().get(name);
		}
		else {
    
    
			// Create attribute instance
			try {
    
    
				attribute = createAttribute(name, parameter, binderFactory, webRequest);
			}
			catch (BindException ex) {
    
    
				if (isBindExceptionRequired(parameter)) {
    
    
					// No BindingResult parameter -> fail with BindException
					throw ex;
				}
				// Otherwise, expose null/empty value and associated BindingResult
				if (parameter.getParameterType() == Optional.class) {
    
    
					attribute = Optional.empty();
				}
				bindingResult = ex.getBindingResult();
			}
		}

		if (bindingResult == null) {
    
    
			// Bean property binding and validation;
			// skipped in case of binding failure on construction.
			WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
			if (binder.getTarget() != null) {
    
    
				if (!mavContainer.isBindingDisabled(name)) {
    
    
					bindRequestParameters(binder, webRequest);
				}
				validateIfApplicable(binder, parameter);
				if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
    
    
					throw new BindException(binder.getBindingResult());
				}
			}
			// Value type adaptation, also covering java.util.Optional
			if (!parameter.getParameterType().isInstance(attribute)) {
    
    
				attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
			}
			bindingResult = binder.getBindingResult();
		}

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

		return attribute;
	}
  • WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
  • WebDataBinder :web数据绑定器,将请求参数的值绑定到指定的JavaBean里面
  • WebDataBinder 利用它里面的 Converters 将请求数据转成指定的数据类型。再次封装到JavaBean中
  • GenericConversionService:在设置每一个值的时候,找它里面的所有converter那个可以将这个数据类型(request带来参数的字符串)转换到指定的类型(JavaBean – Integer)
    byte – > file
    在这里插入图片描述
  • 我们可以在WebDataBinder里面放自己的Converter来实现自己想要的转换
6. 目标方法执行完成

将所有数据都放在ModelAndViewContainer中

  • 包含要去的页面地址
  • 包含Model数据
    在这里插入图片描述
7. 派发处理结果

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);

InternalResourceView:
@Override
	protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    

		// Expose the model object as request attributes.
		exposeModelAsRequestAttributes(model, request);

		// Expose helpers as request attributes, if any.
		exposeHelpers(request);

		// Determine the path for the request dispatcher.
		String dispatcherPath = prepareForRendering(request, response);

		// Obtain a RequestDispatcher for the target resource (typically a JSP).
		RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
		if (rd == null) {
    
    
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		// If already included or response already committed, perform include, else forward.
		if (useInclude(request, response)) {
    
    
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
    
    
				logger.debug("Including [" + getUrl() + "]");
			}
			rd.include(request, response);
		}

		else {
    
    
			// Note: The forwarded resource is supposed to determine the content type itself.
			if (logger.isDebugEnabled()) {
    
    
				logger.debug("Forwarding to [" + getUrl() + "]");
			}
			rd.forward(request, response);
		}
	}
暴露模型作为请求域属性
// Expose the model object as request attributes.
		exposeModelAsRequestAttributes(model, request);
protected void exposeModelAsRequestAttributes(Map<String, Object> model,
			HttpServletRequest request) throws Exception {
    
    

    //model中的所有数据遍历挨个放在请求域中
		model.forEach((name, value) -> {
    
    
			if (value != null) {
    
    
				request.setAttribute(name, value);
			}
			else {
    
    
				request.removeAttribute(name);
			}
		});
	}

猜你喜欢

转载自blog.csdn.net/qq_42451178/article/details/112202805