网站/小程序/APP个性化定制开发,二开,改版等服务,加扣:8582-36016

Spring3引入了一个core.convert包,它提供了一个通用类型转换系统。系统定义一个SPI来实现类型转换逻辑,定义一个API来在运行时执行类型转换。

环境:Springboot2.4.11

Spring3引入了一个core.convert包,它提供了一个通用类型转换系统。系统定义一个SPI来实现类型转换逻辑,定义一个API来在运行时执行类型转换。在Spring容器中,你可以使用此系统作为PropertyEditor实现的替代方案,将外部化的bean属性值字符串转换为所需的属性类型。你还可以在应用程序中需要进行类型转换的任何位置使用公共API。

Converter SPI

实现类型转换逻辑的SPI是简单且强类型的,如以下接口定义所示:

package org.springframework.core.convert.converter; 
public interface Converter<S, T> { 
  T convert(S source); 
}

    要创建自己的转换器,需要实现converter接口,并将S参数化为要转换的类型,将T参数化为要转换的类型。如果需要将S的集合或数组转换为T的集合或集合,还可以透明地应用这样的转换器,前提是同时注册了委托数组或集合转换器(默认情况下,DefaultConversionService会这样做)。

    对于每个转换调用,保证源参数source不为null。如果转换失败,转换器可能会抛出任何未检查的异常。具体来说,它应该抛出IllegalArgumentException以报告无效的源值。注意确保转换器实现是线程安全的。

    为了方便起见,core.convert.support包中提供了几种转换器实现。其中包括从字符串到数字和其他常见类型的转换器。下表显示了StringToInteger类,它是典型的转换器实现:

    package org.springframework.core.convert.support; 
    final class StringToInteger implements Converter<String, Integer> { 
      public Integer convert(String source) { 
        return Integer.valueOf(source); 
      } 
    }

      使用ConverterFactory

      当需要集中整个类层次结构的转换逻辑时(例如,从字符串转换为枚举对象时),可以实现ConverterFactory,如下例所示:

      package org.springframework.core.convert.converter; 
      public interface ConverterFactory<S, R> { 
        <T extends R> Converter<S, T> getConverter(Class<T> targetType); 
      }

        将S参数化为要转换的类型,将R参数化为定义可转换为的类范围的基类型。然后实现getConverter(类),其中T是R的一个子类。

        StringToEnumConverterFactory为例:

        package org.springframework.core.convert.support; 
        
        final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> { 
        
          public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) { 
            return new StringToEnumConverter(targetType); 
          } 
          private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> { 
        
            private Class<T> enumType; 
        
            public StringToEnumConverter(Class<T> enumType) { 
              this.enumType = enumType; 
            } 
        
            public T convert(String source) { 
              return (T) Enum.valueOf(this.enumType, source.trim()); 
            } 
          } 
        }

          自定义类型转换

          现在需要将接受的字符串转换为Users对象

          public class Users { 
            private String name ; 
            private Integer age ; 
          }

            接口

            @GetMapping("/convert2") 
            public Object convert2(Users users) { 
              return users ;  
            }

              调用接口

              Springboot强大的类型转换功能你必须要掌握

              如上,通过get方式users的参数通过逗号分割。接下来就是写类型转换器了

              @SuppressWarnings({"rawtypes", "unchecked"}) 
              public class UsersConverterFactory implements ConverterFactory<String, Users> { 
              
                @Override 
                public <T extends Users> Converter<String, T> getConverter(Class<T> targetType) { 
                  return new StringToUsersConverter() ; 
                } 
                   
                private final class StringToUsersConverter<T extends Users> implements Converter<String, Users> { 
                  public Users convert(String source) { 
                    if (source == null || source.trim().length() == 0) { 
                      return null ; 
                    } 
                    Users user = new Users() ; 
                    // 下面做简单处理,不做校验 
                    String[] values = source.split(",") ; 
                    user.setName(values[0]) ; 
                    user.setAge(Integer.parseInt(values[1])); 
                    return user ; 
                  } 
                } 
              }

                注册类型转换器

                @Configuration 
                public class WebConfig implements WebMvcConfigurer { 
                
                  @Override 
                  public void addFormatters(FormatterRegistry registry) { 
                    registry.addConverterFactory(new UsersConverterFactory()) ; 
                  } 
                     
                }

                  编程方式使用类型转换器

                  要以编程方式使用ConversionService实例,可以像对任何其他bean一样向其注入引用。以下示例显示了如何执行此操作:

                  我们使用系统内置的类型转换器:字符串类型转枚举类型

                  public enum PayStatus { 
                       
                    START, PROCESS, COMPLETE 
                       
                  }

                    @RestController 
                    @RequestMapping("/users") 
                    public class UsersController { 
                         
                      @Resource 
                      private ConversionService cs ; 
                       
                      @GetMapping("/convert") 
                      public Object convert(String status) { 
                        boolean canConvert = cs.canConvert(String.class, PayStatus.class) ; 
                        return canConvert ? cs.convert(status, PayStatus.class) : "UNKNOW";  
                      } 
                       
                    }

                      先判断是否能够转换,其实就是判断有没有从source到target的类型转换器存在。

                      类型转换的实现原理

                      以自定义类型转换器为例

                      SpringMVC在进行接口调用是会执行相应的参数解析,确定了参数解析器后会执行转换服务。

                      查找参数解析器

                      查找合适的HandlerMethodArgumentResolver

                      public class InvocableHandlerMethod extends HandlerMethod { 
                        protected Object[] getMethodArgumentValues(...) throws Exception {   
                          // 查找合适的参数解析器(本例应用的是ServletModelAttributeMethodProcessor) 
                          if (!this.resolvers.supportsParameter(parameter)) { 
                            throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver")); 
                          } 
                          try { 
                            args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); 
                          }       
                        } 
                      }

                        解析参数

                        执行

                        public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResolver { 
                          public final Object resolveArgument(...) { 
                            attribute = createAttribute(name, parameter, binderFactory, webRequest);     
                          } 
                        } 
                        public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodProcessor { 
                          protected final Object createAttribute(String attributeName, MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { 
                            // 这里得到的是原始值 
                            String value = getRequestValueForAttribute(attributeName, request); 
                            if (value != null) { 
                              Object attribute = createAttributeFromRequestValue(value, attributeName, parameter, binderFactory, request); 
                              if (attribute != null) { 
                                return attribute; 
                              } 
                            } 
                            return super.createAttribute(attributeName, parameter, binderFactory, request); 
                          }   
                          protected Object createAttributeFromRequestValue(String sourceValue, String attributeName,MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { 
                            DataBinder binder = binderFactory.createBinder(request, null, attributeName); 
                            // ConversionService对象是在容器启动的时候就初始化好的 
                            // 在WebMvcAutoConfiguration#mvcConversionService方法中初始化。 
                            ConversionService conversionService = binder.getConversionService(); 
                            if (conversionService != null) { 
                              TypeDescriptor source = TypeDescriptor.valueOf(String.class); 
                              TypeDescriptor target = new TypeDescriptor(parameter); 
                              // 判断是否有合适的类型转换器 
                              if (conversionService.canConvert(source, target)) { 
                                // 此方法中进行类型的转换 
                                return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter); 
                              } 
                            } 
                            return null; 
                          } 
                        }


                          评论 0

                          暂无评论
                          0
                          0
                          0
                          立即
                          投稿
                          发表
                          评论
                          返回
                          顶部