react 前端框架如何驱动企业数字化转型与创新发展
621
2022-12-24
SpringBoot与SpringMVC中参数传递的原理解析
目录一:普通参数与基本注解二:复杂参数
一:普通参数与基本注解
HandlerMapping中找到能处理请求的Handler(Controller,method())
为当前Handler找一个适配器HandlerAdapter:RequestMappingHandlerAdapter
1.HandlerAdapter
0-支持方法上标注@RequestMapping
1-支持函数式编程的
xxxx
2.执行目标方法
3.参数解析器:确定要执行的目标方法每一个参数的值是什么
boolean supportsParameter(MethodParameter parameter);
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
先判断是否支持该参数类型, 如果支持, 就调用resolveArgument解析方法
4.返回值处理器
5.挨个判断所有参数解析器哪个支持这个参数:HandlerMethodArgumentResolver: 把控着支持的方法参数类型
请求进来后, 首先从handlerMapping中查找是否有对应的映射处理, 得到映射适配器Adapter,再通过适配器,查找有哪些方法匹配请求,首先判断方法名,以及参数类型是否匹配,首先获得方法中声明的参数名字, 放到数组里,循环遍历27种解析器判断是否有支持处理对应参数名字类型的解析器,如果有的话,根据名字进行解析参数,根据名字获得域数据中的参数, 循环每个参数名字进行判断, 从而为每个参数进行赋值.
对于自定义的POJO类参数:
ServletRequestMethodArgumentResolver 这个解析器用来解析: 是通过主要是通过判断是否是简单类型得到的
@Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.hasParameterAnnotation(ModelAttribute.class) ||
(this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType())));
}
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));
}
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();
}
else {
attribute = ex.getTarget();
}
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
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—某一个类型)
未来我们可以给WebDataBinder里面放自己的Converter
private static final class StringToNumber implements Converter
converter总接口:
@FunctionalInterface
public interface Converter {
//自定义转换器:实现按照自己的规则给相应对象赋值
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter
@Override
public Pet convert(String source) {
if (!StringUtils.isEmpty(source)){
Pet pet = new Pet();
String[] split = source.split(",");
pet.setName(split[0]);
pet.setAge(split[1]);
return pet;
}
return null;
}
});
}
二:复杂参数
Map/Model(map/model里面的数据会被放在request的请求域 相当于request.setAttribute)/Errors/BindingResult/RedirectAttributes(重定向携带数据)/ServletRespons().SessionStaus.UriComponentsBuilder
6.在上面第五步目标方法执行完成后:
将所有的数据都放在ModelAdnViewContainer;包含要去的页面地址View,还包含Model数据
7.处理派发结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
在页面进行响应前, 进行视图渲染的时候:
exposeModelAsRequestAttributes(model, request); 该方法将model中所有参数都放在请求域数据中
protected void renderMergedOutputModel(
Map
// 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);
}
}
通过循环遍历model中的所有数据放在请求域中
protected void exposeModelAsRequestAttributes(Map
HttpServletRequest request) throws Exception {
model.forEach((name, value) -> {
if (value != null) {
request.setAttribute(name, value);
}
else {
request.removeAttribute(name);
}
});
}
不管我们在方法形参位置放 Map集合或者Molde 最终在底层源码都是同一个对象在mvcContainer容器中进行保存
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~