PropertyMapper
是Spring提供的一个工具类,主要用于重新赋值,转换等操作,位于org.springframework.boot.context.properties.PropertyMapper
下。
我第一次发现这个类是在spring-boot-starter-amqp
中,配置RabbitTemplate
中看到的
代码位于org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration.RabbitTemplateConfiguration
@Bean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
@ConditionalOnMissingBean(RabbitOperations.class)
public RabbitTemplate rabbitTemplate(RabbitProperties properties,
ObjectProvider<MessageConverter> messageConverter,
ObjectProvider<RabbitRetryTemplateCustomizer> retryTemplateCustomizers,
ConnectionFactory connectionFactory) {
PropertyMapper map = PropertyMapper.get();
RabbitTemplate template = new RabbitTemplate(connectionFactory);
messageConverter.ifUnique(template::setMessageConverter);
template.setMandatory(determineMandatoryFlag(properties));
RabbitProperties.Template templateProperties = properties.getTemplate();
if (templateProperties.getRetry().isEnabled()) {
template.setRetryTemplate(
new RetryTemplateFactory(retryTemplateCustomizers.orderedStream().collect(Collectors.toList()))
.createRetryTemplate(templateProperties.getRetry(),
RabbitRetryTemplateCustomizer.Target.SENDER));
}
map.from(templateProperties::getReceiveTimeout).whenNonNull().as(Duration::toMillis)
.to(template::setReceiveTimeout);
map.from(templateProperties::getReplyTimeout).whenNonNull().as(Duration::toMillis)
.to(template::setReplyTimeout);
map.from(templateProperties::getExchange).to(template::setExchange);
map.from(templateProperties::getRoutingKey).to(template::setRoutingKey);
map.from(templateProperties::getDefaultReceiveQueue).whenNonNull().to(template::setDefaultReceiveQueue);
return template;
}
那一个个的 from….to…让我很好奇,于是便研究了一下他的用法。
在实际工作中,经常会遇到将数据库的实体类Entity转成DTO类的操作,通常情况。我们有可以将属性一个个get出来,在set进去。还有一种就是用BeanUtils工具类将对应类型的属性一个个copy进去。
了解了PropertyMapper
之后,我们有多了一种方法转换了。
先建立两个类,Order和OrderDTO
Order.java
@Data
public class Order {
private Long id;
private BigDecimal totalAmout;
private Integer status;
private Long userId;
private LocalDateTime createTime;
}
OrderDTO.java
@Data
public class OrderDTO {
private Long id;
private BigDecimal totalAmout;
private Integer status;
private Long userId;
private String createTime;
}
使用PropertyMapper
转换
Order order = new Order();
order.setId(1L);
order.setStatus(1);
order.setTotalAmout(BigDecimal.ONE);
order.setUserId(100L);
order.setCreateTime(LocalDateTime.now());
PropertyMapper propertyMapper = PropertyMapper.get();
OrderDTO orderDTO = new OrderDTO();
propertyMapper.from(order::getId).to(orderDTO::setId);
// 如果from获取到的元素不是null,则执行to里面的动作
propertyMapper.from(order::getStatus).whenNonNull().to(orderDTO::setStatus);
propertyMapper.from(order::getUserId).to(orderDTO::setUserId);
propertyMapper.from(order::getTotalAmout).to(orderDTO::setTotalAmout);
// 因为Order里面的createTime是LocalDateTime类型,OrderDTO里面则是String类型,需要转换一下
propertyMapper.from(order::getCreateTime).as(createTime -> {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return createTime.format(formatter);
}).to(orderDTO::setCreateTime);
这样一来就可以通过PropertyMapper
将Order对象的值set到OrderDTO对象中。
PropertyMapper
常用方法
<T> Source<T> from(Supplier<T> supplier)
:提供值的来源,入参为Supplier
<T> Source<T> from(T value)
:一种重载形式,入参可以为一个对象void to(Consumer<T> consumer)
:通过将任何未过滤的值传递给指定的使用者来完成映射<R> R toInstance(Function<T, R> factory)
:通过从未过滤的值创建新实例来完成映射void toCall(Runnable runnable)
:当值还没有时,通过调用指定的方法来完成映射<R> Source<R> as(Function<T, R> adapter)
:将T类型的入参转成R类型的出参,类似于Stream中的mapSource<T> when...
:这一系列方法,都是过滤用的。在from
后面调用,如果满足条件,就直接to
方法static PropertyMapper get()
:提供PropertyMapper
实例PropertyMapper alwaysApplyingWhenNonNull()
:提供实例时,当前实例就过滤掉from
之后是null的元素。PropertyMapper.get().alwaysApplyingWhenNonNull();
PropertyMapper alwaysApplying(SourceOperator operator)
:自定义过滤规则,参考代码
PropertyMapper propertyMapper = PropertyMapper.get().alwaysApplying(new PropertyMapper.SourceOperator() {
@Override
public <T> PropertyMapper.Source<T> apply(PropertyMapper.Source<T> source) {
return source.when(t -> t instanceof LocalDateTime);
}
});
就好比,当前 PropertyMapper
只会映射 LocalDateTime
类型的字段。
注意:如果from
方法后面有when
条件,则alwaysApplying
中设置的初始化提交将会失效。
Spring里面还有各式各样的类似这样的高逼格,方便使用的小工具。多多阅读Spring源码,就可以发现好多。