カスタムカプセル化されたオブジェクト
ページによって送信されたリクエストデータがカスタムオブジェクトにカプセル化されているのはなぜですか?
カスタムオブジェクトはこれによって処理され、
カスタムオブジェクトはカプセル化され
、単純なデータ型であるかどうかを判断します。
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バインダー=binderFactory.createBinder(webRequest、属性、名前);
このバインダーを見てみましょう
これがデータを置くために作成されたオブジェクトです。
私たちはすべてhttpから送信されます。つまり、送信されるデータはすべてString型です。
これがコンバーターです。
ここには124個のコンバーターがあることがわかります。たとえば、選択したのはStringをEnumに変換する
ことであり、StringをObjectに変換することもできます。
次のボックスは、受信したリクエスト文字列データを、 String into Integerなど、指定したオブジェクトのデータ型に変換する役割を果たします。
このステップのバインダーは、オブジェクトとネイティブリクエストを配置するために作成したものです。
このステップの後、データ
をバインドしました。これは、リフレクション呼び出しメソッドを介してデータの値をバインドすることです。
カプセル化プロセスが使用されます。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;
}
}
要約する
WebDataBinder:Webデータ・バインダーは、要求パラメーターの値を指定されたJavaBeanにバインドします
WebDataBinderは、その中のコンバーターを使用して、要求データを指定されたデータ型に変換します。再びJavaBeanにカプセル化
GenericConversionService:各値を設定するときに、このデータ型(要求によってもたらされたパラメーターを含む文字列)を指定された型(JavaBean-整数)に変換できるすべてのコンバーターを検索します。
カスタムコンバーターの原理
カスタムパーサーを分離するために使用します
@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;
}
});
}
};
}
パーサーを調べたところ、125は元々カスタムパーサーの124であり、ここに配置しました。
ここでそれを裏返し
、送ります