mapstruct+lombok+validator,简化代码三剑客

mapstruct+lombok+validator,简化代码三剑客

想必大家一定见过这样的代码:

		customerDO.setId( customerDTO.getId() );
        customerDO.setName( customerDTO.getName() );
        customerDO.setPhone( customerDTO.getPhone() );
        customerDO.setShopCode( customerDTO.getShopCode() );
        customerDO.setReference( customerDTO.getReference() );
        customerDO.setDuty( customerDTO.getDuty() );
        customerDO.setIsDefeat( customerDTO.getIsDefeat() );
        ···

这样的:

		if(null == id) {
			throw ParamMissingException("id不能为空")}
		if(null == name) {
			throw ParamMissingException("名称不能为空")}
		if(null == phone) {
			throw ParamMissingException("手机号不能为空")}
		...
		

还有这样的:

	public void setId(Long id) {
        this.id = id;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
	public Long getId() {
        return this.id;
    }
    public String getName() {
        return this.name;
    }
    public String getPhone() {
        return this.phone;
    }
    ...

尤其是前两种代码,可能与我们的业务逻辑并无相关,却占据了很多地方。我称这种代码为项目的“脂肪块"。当这种代码大量充斥我们的项目时,我们的项目会看起来很臃肿。当你接手一个项目时,如果存在大量这种代码,想要理清业务逻辑,必须穿过它们的包围。这使我们很痛苦。那么有没有办法简化这种代码呢?接下来,我就为大家介绍几个简单好用的工具。


mapstruct

普通类型转换

mapstruct是一个用于自定义bean映射的框架。简单的讲,就是用于数据类型转换,解决上面演示的第一种“脂肪块"。这篇文章以应用为主,不涉及过多理论解释。直接上使用步骤:
1、引入依赖

			
				org.mapstruct
				mapstruct-jdk8
				1.2.0.Final
			
			
				org.mapstruct
				mapstruct-processor
				1.2.0.Final
			

2、定义一个interface,接口名自定义。加上@Mapper注解。在其中定义转换数据类型的方法。入参为原数据类型,返回值目标数据类型。方法名自定义。

@Mapper
public interface CustomerMapper {
    CustomerMapper INSTANCE = Mappers.getMapper(CustomerMapper.class);
    
    CustomerDO toDO(CustomerDTO customerDTO);

    List<CustomerDO> toDOs(List<CustomerDTO> carDTOList);
    
    CustomerDTO toDTO(CustomerDO customerDO);

    List<CustomerDTO> toDTOs(List<CustomerDO> customerDO);
}

3、编译项目。
4、调用方法。

	CustomerDTO customerDTO = CustomerMapper.INSTANCE.toDTO(customerDO);

原本需要写的多行代码(开头演示的第一种代码),被这一行所代替。除了大大简化代码之外,使用这个框架还有一个很大的好处就是:当你需要调整字段时,只需在DO和DTO里调整就好,不必再去业务方法里增加或减少set··(get··)这种代码,降低了维护的难度。

枚举类型转换

上面的转换需要字段类型和字段名称一致。但有时我们需要把枚举类型转换为数字或字符串。
1、枚举转数字
方法一:
在枚举类加上code字段

public enum NumberEnum {
	ONE(1),
	TWO(2);
	private Integer code;
	NumberEnum(Integer code) {
		this.code = code;
	}
}

然后在Mapper接口中加上这样的注解:

	@Mapping(source = "numberEnum.code", target = "number")
	UserDO toDO(UserDTO userDTO);

方法二:
在Mapper中加转换方法:

	default Integer getNumberOrdinal(NumberEnum numberEnum) {
        if (NumberEnums == null) {
            return null;
        }
        return numberEnums.ordinal();
    }

这两种方法的区别:
方法一可以自定义要转换的数字,而方法二只能转换为枚举值的序数。
2、枚举转字符串
情况一:转为枚举值的name
框架支持直接转换,不需要特殊处理
情况二:转为汉字文本
同转数字的方法一,在枚举类中定义desc字段:

public enum NumberEnum {
	ONE(1,),
	TWO(2,贰);
	private Integer code;
	private String desc;
	NumberEnum(Integer code, String desc) {
		this.code = code;
		this.desc = desc;
	}
}

在Mapper中加注解:

	@Mapping(source = "numberEnum.desc", target = "number")
	UserDO toDO(UserDTO userDTO);

使用mapstruct踩到的坑

在使用default关键字在接口中增加转换方法的时候,框架会根据方法的入参和返回值来寻找要转换的字段。这样有时会在不需要使用方法转换的字段上也使用这个方法,要小心避免。

lombok

lombok与mapstruct原理相同,也是在编译的时候帮助用户生成代码。lombok主要用在数据类型上,简化一些重复的代码。
比如:

@Data
public class TaskDTO implements Serializable {
	private static final long serialVersionUID = 8460254643609851598L;
	private String uuid;
	private String userId;
	private TasksEnums tasksEnums;
}

@Date注解会帮我们生成get、set、equals、hashCode、toString等方法。
虽然这些方法可以通过IDE生成,但是在改动字段时,还需要重新生成。使用@Date注解,更容易扩展。

validation

我们在写方法时,首先要对传入的参数进行校验。这些代码会占用大量的篇幅。validation是把参数检验的工作提到了框架层面。
首先,我们需要引两个包:

			
			<validation.api.version>1.0.0.GAvalidation.api.version>
			<hibernate.validator.version>4.2.0.Finalhibernate.validator.version>
			<dependency>
				<groupId>javax.validationgroupId>
				<artifactId>validation-apiartifactId>
				<version>${validation.api.version}version>
			dependency>
			<dependency>
				<groupId>org.hibernategroupId>
				<artifactId>hibernate-validatorartifactId>
				<version>${hibernate.validator.version}version>
			dependency>

然后在需要校验的参数上加上注解:

	@NotNull(message = "买家手机号不能为空")
    private String phone;

除了@NotNull注解,validation还提供了正则、日期、数字区间等注解,可以满足开发中的各种情况。
最后在发布dubbo服务配置文件里加上:

<dubbo:service interface="com.xx.xx.xx.xx.XxService" ref="XxService" validation="true"/>

总结感想

我们开发中经常会遇到重复性的代码,这时我们要想着能否在框架层面解决这个问题。不仅仅是为了少写代码,还能使我们的代码更好阅读,更好维护,更好扩展。

你可能感兴趣的:(工作)