专业的JAVA编程教程与资源

网站首页 > java教程 正文

对象转换利器MapStruct之自定义映射器

temp10 2024-10-03 01:21:39 java教程 11 ℃ 0 评论

前言

之前分享了一篇关于MapStruct的入门实践文章,关于如何使用MapStruct将一个对象的属性值,赋予到另一个对象中,而不用传统的getter、setter等。

对象转换利器mapStruct

对象转换利器MapStruct之自定义映射器

本文分享另一个常见的开发场景,就是我们将一个值赋予到另一个的对象的同时,需要再做一层转换,如将一个数据库中存储的对象,转换为一个前台可以展示的对象,等等。

案例

1.数据库存储对象

我们定义一个数据库中存储的对象,确保它可以顺利地通过MyBatis或者JPA等Dao框架,写到对应的库表结构中。

package com.example.springbootmapstructenum.domain;

import lombok.Data;

import java.util.Date;

/**
 * 活动存储类
 *
 * @author hongcunlin
 */
@Data
public class Activity {
    /**
     * 活动id
     */
    private Long id;

    /**
     * 活动名称
     */
    private String name;

    /**
     * 活动状态
     *
     * @see com.example.springbootmapstructenum.enums.ActivityStatusEnum
     */
    private Integer status;

    /**
     * 活动创建时间
     */
    private Date createTime;
}

这里有个点,就是这个活动状态status,我们为了减少数据库如MySQL等的存储空间,通常会存储一些枚举值,如1,2,3等,而不是存储中文说明的字符串。

package com.example.springbootmapstructenum.enums;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

/**
 * 活动状态枚举
 *
 * @author hongcunlin
 */
@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum ActivityStatusEnum {
    /**
     * 进行中
     */
    RUNNING(1, "进行中"),

    /**
     * 已结束
     */
    CLOSED(2, "已结束");

    /**
     * 活动状态值
     */
    private Integer value;

    /**
     * 活动状态名称
     */
    private String name;

    /**
     * 活动状态值转名称
     *
     * @param value 活动状态值
     * @return 活动状态名称
     */
    public static String getNameByValue(Integer value) {
        for (ActivityStatusEnum activityStatusEnum : values()) {
            if (activityStatusEnum.getValue().equals(value)) {
                return activityStatusEnum.getName();
            }
        }
        return "活动状态不存在";
    }
}

我们也对应的编写了该字段的枚举类。

2.前台展示对象

我们定义了一个前台展示的对象,确保它可以直接的返回给前台去展示,中间无需做其他转换加工。

package com.example.springbootmapstructenum.vo;

import lombok.Data;

import java.util.Date;

/**
 * 活动展示类
 *
 * @author hongcunlin
 */
@Data
public class ActivityVO {
    /**
     * 活动id
     */
    private Long id;

    /**
     * 活动名称
     */
    private String name;

    /**
     * 活动状态(这里需要将Integer转换为对应String)
     */
    private String status;

    /**
     * 创建时间
     */
    private Date createTime;
}

这里有个点,就是这个活动状态status,直接面对C端用户了,所以它是一个字符串,而不是数据库里边存储的枚举值了,这就和数据库里边存储的有区别了,需要做一个关系映射。

3.数据映射

通过前面的的说明,我明确了本次的需求,就是将一个数据库中存储的对象,转换为一个前台可以直接展示的对象,我们引入了MapStruct这个利器,下面是它的依赖:

<!--对象转换-->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.3.Final</version>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.3.Final</version>
</dependency>

借此我们编写对象转换工具

package com.example.springbootmapstructenum.utils;

import com.example.springbootmapstructenum.domain.Activity;
import com.example.springbootmapstructenum.enums.ActivityStatusEnum;
import com.example.springbootmapstructenum.vo.ActivityVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;

/**
 * 对象转换工具
 *
 * @author hongcunlin
 */
@Mapper
public interface ConvertUtils {
    /**
     * 对象转换实例
     */
    ConvertUtils INSTANCE = Mappers.getMapper(ConvertUtils.class);

    /**
     * 将库里的对象转换为前台展示的对象
     *
     * @param activity 库对象
     * @return 前台对象
     */
    @Mapping(source = "status", target = "status", qualifiedByName = "getStatusName")
    ActivityVO convert(Activity activity);

    /**
     * 获取活动名称
     *
     * @param value 活动值
     * @return 活动名称
     */
    @Named("getStatusName")
    default String getStatusName(Integer value) {
        return ActivityStatusEnum.getNameByValue(value);
    }
}

这里有个点,就是通过@Mapping注解,指定了对象转换的字段是哪两个(status,status),至于转换的方法又是哪个(getStatusName)。

4.测试

我们对编写的对象转换工具进行测试,

package com.example.springbootmapstructenum.utils;

import com.example.springbootmapstructenum.domain.Activity;
import org.junit.jupiter.api.Test;

import java.util.Date;

public class ConvertUtilsTest {
    @Test
    public void test() {
        Activity activity = new Activity();
        activity.setId(123L);
        activity.setName("双十一大促活动");
        activity.setStatus(1);
        activity.setCreateTime(new Date());

        System.out.println(activity);
        System.out.println(ConvertUtils.INSTANCE.convert(activity));
    }
}

测试结果如下

可以看到,我们的status已经成功转化为对应的中文字符串了。

其他

本文基于原先的基础文章MapStruct转换,进一步说明了自定义映射的器的用法,这也是实际业务开发中一个特别常见的场景。使用好这些方式,可以让我们的代码变得更加清晰可维护,笔者有空再继续分享开发中常见的场景。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表