复习的面试资料
这些面试全部出自大厂面试真题和面试合集当中,小编已经为大家整理完毕(PDF版)
- 第一部分:Java基础-中级-高级
- 第二部分:开源框架(SSM:Spring+SpringMVC+MyBatis)
- 第三部分:性能调优(JVM+MySQL+Tomcat)
- 第四部分:分布式(限流:ZK+Nginx;缓存:Redis+MongoDB+Memcached;通讯:MQ+kafka)
- 第五部分:微服务(SpringBoot+SpringCloud+Dubbo)
- 第六部分:其他:并发编程+设计模式+数据结构与算法+网络
进阶学习笔记pdf
- Java架构进阶之架构筑基篇(Java基础+并发编程+JVM+MySQL+Tomcat+网络+数据结构与算法)
- Java架构进阶之开源框架篇(设计模式+Spring+SpringMVC+MyBatis)
- Java架构进阶之分布式架构篇 (限流(ZK/Nginx)+缓存(Redis/MongoDB/Memcached)+通讯(MQ/kafka))
- Java架构进阶之微服务架构篇(RPC+SpringBoot+SpringCloud+Dubbo+K8s)
org.mapstruct
mapstruct
${org.mapstruct.version}
org.projectlombok
lombok
${org.projectlombok.version}
provided
junit
junit
test
4.12
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
1.81.8
org.mapstruct
mapstruct-processor
${org.mapstruct.version}
org.projectlombok
lombok
${org.projectlombok.version}
java代码如下:
定义Person实体
@Data
public class Person {
private String name;
private String lastName;
}
定义PersonDTO
@Data
public class PersonDTO {
private String firstName;
private String lastName;
}
使用MapStruct定义Person和PersonDTO之间的转换接口
@Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
@Mapping(source = “firstName”,target = “name”)
Person personDTOToPerson(PersonDTO personDTO);
}
使用上面定义的转换器,例子如下
public class PersonMapperTest {
@Test
public void personDTOToPerson() {
PersonMapper personMapper = PersonMapper.INSTANCE;
PersonDTO personDTO = new PersonDTO();
personDTO.setFirstName(“feng”);
personDTO.setLastName(“xiu”);
Person person = personMapper.personDTOToPerson(personDTO);
Assert.assertEquals(person.getLastName(),personDTO.getLastName());
Assert.assertEquals(person.getName(),personDTO.getFirstName());
}
}
从上面的例子可以看出,使用MapStruct定义一个对象转换器,分为以下几步
-
创建一个对象转换接口,使用@Mapper注解
-
定义转换方法,设置需要转换的对象作为参数,返回值是转换后的对象
-
使用@Mapping注解方法,设置转换对应的属性,如果属性名相同,则不需要设置。
-
接口中定义一个属性,使用Mappers.getMapper方获取对应的实现,方便使用。
通过上面4步,就可以定义出一个对象转换器,相比于之前来说简单很多。
定义Mapper(Bean映射器)
上面已经看了一个简单的demo,下面我们来具体了解下,如何创建或者说定义一个对象转换器,也就是定义一个Mapper。
▐ 基本的映射
创建一个bean的转换器,只需要定义一个接口,并将需要的转换方法定义在接口中,然后使用org.mapstruct.Mapper
注释对其进行注释。
比如上面的PersonMapper
@Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
@Mapping(source = “firstName”,target = “name”)
Person personDTOToPerson(PersonDTO personDTO);
}
@Mapper注解作用是:在build-time时,MapStruct会自动生成一个实现PersonMapper接口的类。
接口中定义的方法,在自动生成时,默认会将source对象(比如PersonDTO)中所有可读的属性拷贝到target(比如Person)对象中相关的属性,转换规则主要有以下俩条:
-
当target和source对象中属性名相同,则直接转换
-
当target和source对象中属性名不同,名字的映射可以通过@Mapping注解来指定。比如上面firstName映射到name属性上。
其实上面PersonMapper通过MapStruct生成的类和我们自己写一个转换类是没有什么区别,上面PersonMapper自动生成的实现类如下:
public class PersonMapperImpl implements PersonMapper {
public PersonMapperImpl() {
}
public Person personDTOToPerson(PersonDTO personDTO) {
if (personDTO == null) {
return null;
} else {
Person person = new Person();
person.setName(personDTO.getFirstName());
person.setLastName(personDTO.getLastName());
return person;
}
}
}
从上面可以看出,MapStruct的哲学是尽可能的生成看起来和手写的代码一样。因此,这也说明MapStruct映射对象属性使用的是getter/setter而不是反射。
正如上面例子这种显示的,在进行映射的时候,也会考虑通过@Mapping中指定的属性。如果指定的属性类型不同,MapStruct可能会通过隐式的类型转换,这个会在后面讲,或者通过调用/创建另外一个映射方法个,这个会在映射对象引用这一节说道。当一个bean的source和target属性是简单类型或者是Bean,才会创建一个新的映射方法,比如属性不能是Collection或者Map类型的属性。至于集合类型的映射将在后面讲。
MapStruct映射target和source的所有公共属性。这包括在父类型上声明的属性。
▐ 在Mapper中自定义转换属性方法
当俩种类型的映射不能通过MapStruct自动生成,我们需要自定义一些方法。自定义方法的方式主要有以下俩种。
如果其他Mapper中已经有此方法,可以在@Mapper(uses=XXXMapper.class)
来调用自定义的方法,这样可以方法重用。这个后面会说。
java8或者更新的版本,可以直接在Mapper接口中添加default方法。当参数和返回值类型匹配,则生成的代码会自动调用这个方法。
例子如下
@Mapper
public interface CarMapper {
@Mapping(…)
…
CarDto carToCarDto(Car car);
default PersonDto personToPersonDto(Person person) {
//hand-written mapping logic
}
}
在MapStruct自动生成代码,需要将Person转换成PersonDTO对象时,就会直接调用default方法。
也可以使用抽象类来定义,比如上面的例子使用抽象类定义如下
@Mapper
public abstract class CarMapper {
@Mapping(…)
…
public abstract CarDto carToCarDto(Car car);
public PersonDto personToPersonDto(Person person) {
//hand-written mapping logic
}
}
▐ 多个source参数的映射方法
MapStruct也支持带有多个source参数的映射方法。这个在将多个bean合并成一个bean的时候非常有用。
例子如下:
@Mapper
public interface AddressMapper {
@Mapping(source = “person.description”, target = “description”)
@Mapping(source = “address.houseNo”, target = “houseNumber”)
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);
}
上面显示的就是将俩个source参数映射成一个target对象。和单个参数一样,属性映射也是通过名称。
如果多个source参数中的属性具有相同的名称,必须通过@Mapping指定哪个source里面的属性映射到target属性中。如果存在多个相同的属性,并且没有指定,则会报错。
MapStruct也支持直接引用一个source参数映射到target对象中。例子如下
@Mapper
public interface AddressMapper {
@Mapping(source = “person.description”, target = “description”)
@Mapping(source = “hn”, target = “houseNumber”)
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);
}
上面的例子将hn直接映射到target的houseNumber属性上。
▐ 处理内嵌bean属性映射
例子如下:
@Mapper
public interface CustomerMapper {
@Mapping( target = “name”, source = “record.name” )
@Mapping( target = “.”, source = “record” )
@Mapping( target = “.”, source = “account” )
Customer customerDtoToCustomer(CustomerDto customerDto);
}
-
如果只是某一个内嵌属性的映射,可以类似
@Mapping( target = "name", source = "record.name" )
这样写 -
如果是映射多个内嵌属性到target上,可以用
.
代替,表示把对应属性bean匹配的内嵌属性映射到target上
▐ 更新Bean实例
有时我们并不一定创建一个新的Bean,可能需要更新某一个实例。这种类型的映射我们可以通过在参数上增加一个@MappingTarget注解。例子如下:
@Mapper
public interface CarMapper {
void updateCarFromDto(CarDto carDto, @MappingTarget Car car);
}
这个例子会把CarDto中的属性值更新的Car对象实例上。上面的例子我们也可以将void改成Car类型返回值。
对于Collection或者Map类型,默认会将集合中所有的值清空,然后使用相关source集合中的值来填充,即CollectionMappingStrategy.ACCESSOR_ONLY策略。另外也提供了CollectionMappingStrategy.ADDER_PREFERRED 或者 CollectionMappingStrategy.TARGET_IMMUTABLE。这些策略可以在@Mapper(collectionMappingStrategy=CollectionMappingStrategy.TARGET_IMMUTABLE)来指定。
▐ 集合映射
基本的定义方式和普通的bean没什么区别,简单例子如下
@Mapper
public interface CarMapper {
Set integerSetToStringSet(Set integers);
List carsToCarDtos(List cars);
CarDto carToCarDto(Car car);
}
对应的生成方法如下
//GENERATED CODE
@Override
public Set integerSetToStringSet(Set integers) {
if ( integers == null ) {
return null;
}
Set set = new HashSet();
for ( Integer integer : integers ) {
set.add( String.valueOf( integer ) );
}
return set;
}
@Override
public List carsToCarDtos(List cars) {
if ( cars == null ) {
return null;
}
List list = new ArrayList();
for ( Car car : cars ) {
list.add( carToCarDto( car ) );
}
return list;
}
对于Map的映射,还提供了@MapMapping
注解,用于处理value的转换
具体的例子如下
public interface SourceTargetMapper {
@MapMapping(valueDateFormat = “dd.MM.yyyy”)
Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source);
}
生成的代码如下
//GENERATED CODE
@Override
public Map<Long, Date> stringStringMapToLongDateMap(Map<String, String> source) {
if ( source == null ) {
return null;
}
Map<Long, Date> map = new HashMap<Long, Date>();
for ( Map.Entry<String, String> entry : source.entrySet() ) {
Long key = Long.parseLong( entry.getKey() );
Date value;
try {
value = new SimpleDateFormat( “dd.MM.yyyy” ).parse( entry.getValue() );
}
catch( ParseException e ) {
throw new RuntimeException( e );
}
map.put( key, value );
}
return map;
}
通过@Mapping#collectionMappingStrategy设置集合的映射策略:CollectionMappingStrategy.ACCESSOR_ONLY:默认、CollectionMappingStrategy.SETTER_PREFERRED、CollectionMappingStrategy.ADDER_PREFERRED、CollectionMappingStrategy.TARGET_IMMUTABLE。
策略具体的意义如果没有看懂,可以参考下这篇文章MapStruct文档(五)——集合映射
▐ 枚举映射处理
直接上例子,方便理解
@Mapper
public interface OrderMapper {
OrderMapper INSTANCE = Mappers.getMapper( OrderMapper.class );
@ValueMappings({
@ValueMapping(source = “EXTRA”, target = “SPECIAL”),
@ValueMapping(source = “STANDARD”, target = “DEFAULT”),
@ValueMapping(source = “NORMAL”, target = “DEFAULT”)
})
ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
}
生成的代码如下
// GENERATED CODE
public class OrderMapperImpl implements OrderMapper {
@Override
public ExternalOrderType orderTypeToExternalOrderType(OrderType orderType) {
if ( orderType == null ) {
return null;
}
ExternalOrderType externalOrderType_;
switch ( orderType ) {
case EXTRA: externalOrderType_ = ExternalOrderType.SPECIAL;
break;
case STANDARD: externalOrderType_ = ExternalOrderType.DEFAULT;
break;
case NORMAL: externalOrderType_ = ExternalOrderType.DEFAULT;
break;
case RETAIL: externalOrderType_ = ExternalOrderType.RETAIL;
break;
case B2B: externalOrderType_ = ExternalOrderType.B2B;
break;
default: throw new IllegalArgumentException( "Unexpected enum constant: " + orderType );
}
return externalOrderType_;
}
}
默认情况下,如果存在不匹配的情形,则直接抛出异常。这种默认行为是可以被修改的,主要有以下三种策略
-
MappingConstants.NULL : 处理null值,
-
MappingConstants.ANY_REMAINING : 处理所有未被定义或者名字匹配不上的
-
MappingConstants.ANY_UNMAPPED :处理任何违背匹配的情形
枚举到字符串的映射,不支持MappingConstants.ANY_REMAINING
@Mapper
public interface TestMapper {
@ValueMappings({
@ValueMapping(source = “able_status”, target = “PERFECT”),
@ValueMapping(source = MappingConstants.NULL, target = “PASS”),
@ValueMapping(source = “failed_status”, target = MappingConstants.NULL),
@ValueMapping(source = MappingConstants.ANY_UNMAPPED, target = “normal”),
})
String toEnum(DisableStatus disableStatus);
}
@Component
public class TestMapperImpl implements TestMapper {
@Override
public String toEnum(DisableStatus disableStatus) {
if ( disableStatus == null ) {
return “PASS”;
}
String string;
switch ( disableStatus ) {
case able_status: string = “PERFECT”;
break;
case failed_status: string = null;
break;
default: string = “normal”;
}
最后
这份文档从构建一个键值数据库的关键架构入手,不仅带你建立起全局观,还帮你迅速抓住核心主线。除此之外,还会具体讲解数据结构、线程模型、网络框架、持久化、主从同步和切片集群等,帮你搞懂底层原理。相信这对于所有层次的Redis使用者都是一份非常完美的教程了。
整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
你的支持,我的动力;祝各位前程似锦,offer不断!!!
tatus", target = “PERFECT”),
@ValueMapping(source = MappingConstants.NULL, target = “PASS”),
@ValueMapping(source = “failed_status”, target = MappingConstants.NULL),
@ValueMapping(source = MappingConstants.ANY_UNMAPPED, target = “normal”),
})
String toEnum(DisableStatus disableStatus);
}
@Component
public class TestMapperImpl implements TestMapper {
@Override
public String toEnum(DisableStatus disableStatus) {
if ( disableStatus == null ) {
return “PASS”;
}
String string;
switch ( disableStatus ) {
case able_status: string = “PERFECT”;
break;
case failed_status: string = null;
break;
default: string = “normal”;
}
最后
这份文档从构建一个键值数据库的关键架构入手,不仅带你建立起全局观,还帮你迅速抓住核心主线。除此之外,还会具体讲解数据结构、线程模型、网络框架、持久化、主从同步和切片集群等,帮你搞懂底层原理。相信这对于所有层次的Redis使用者都是一份非常完美的教程了。
[外链图片转存中…(img-e0Pwbep6-1715332576154)]
整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
你的支持,我的动力;祝各位前程似锦,offer不断!!!