Directorio de artículos
objeto encapsulado personalizado
¿Por qué los datos de solicitud enviados por la página están encapsulados en nuestro objeto personalizado?
Nuestro objeto personalizado es procesado por esto.
Nuestro objeto personalizado está encapsulado con él.
Juzgará si es un tipo de datos simple o no.
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));
}
El núcleo de la encapsulación de tipo personalizado está aquí
@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;
}
este es nuestro núcleo
Carpeta WebDataBinder = binderFactory.createBinder(webRequest, atributo, nombre);
Echemos un vistazo a esta carpeta.
Aquí está el objeto creado para poner los datos
, todos somos enviados desde http, es decir, todos los datos enviados son de tipo String,
este es nuestro convertidor.
Vemos que hay 124 convertidores aquí, por ejemplo, el que seleccionamos es para convertir String a Enum,
y también hay String a Object.
El siguiente cuadro es responsable de convertir los datos de cadena de solicitud recibidos en el tipo de datos en el objeto que especificamos,
como Cadena en Entero
El binder en este paso es el que creamos para poner nuestro objeto y la solicitud nativa
Después de este paso, hemos vinculado los datos
, que consiste en vincular el valor de nuestros datos a través del método de llamada de reflexión. Se
utiliza el proceso de encapsulación .ServletModelAttributeMethodProcessor
public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodProcessor {
@Override//本方法在ModelAttributeMethodProcessor类,
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.hasParameterAnnotation(ModelAttribute.class) ||
(this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType())));
}
@Override
@Nullable//本方法在ModelAttributeMethodProcessor类,
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
...
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 (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)) {
//web数据绑定器,将请求参数的值绑定到指定的JavaBean里面**
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;
}
}
Resumir
WebDataBinder: el archivador de datos web vincula el valor del parámetro de solicitud al JavaBean especificado
WebDataBinder utiliza los convertidores que contiene para convertir los datos solicitados en el tipo de datos especificado. Nuevamente encapsulado en JavaBean
GenericConversionService: al configurar cada valor, busque todos los convertidores que puedan convertir este tipo de datos (cadena con parámetros traídos por la solicitud) al tipo especificado (JavaBean - Integer)
Principio del convertidor personalizado
Usamos, para separar
nuestro analizador personalizado
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<String, Pet>() {
@Override
public Pet convert(String source) {
if(!StringUtils.isEmpty(source)){
Pet pat = new Pet();
String [] split = source.split(",");
pat.setName(split[0]);
pat.setAge(String.valueOf(Integer.valueOf(split[1])));
return pat;
}
return null;
}
});
}
};
}
Examinamos el analizador y descubrimos que 125 eran originalmente 124 de nuestros analizadores personalizados y lo pusimos aquí
Aquí le damos la vuelta
y lo enviamos