zl程序教程

您现在的位置是:首页 >  Java

当前栏目

SpringBoot实战:整合MapStruct实现数据类型转化

2023-02-18 15:37:17 时间

MapStruct 是一个代码生成器,它基于约定优于配置方法极大地简化了 Java bean 类型之间映射的实现。自动生成的映射转换代码只使用简单的方法调用,因此速度快、类型安全而且易于理解阅读;本篇就是实现 SpringBoot 整合 MapStruct 实现数据类型转化。 项目源码实现前分支地址:https://toscode.gitee.com/li_ziheng/lizhengi-samples/tree/feature%2Fspring-boot-1.0.0/ 项目源码实现后分支地址:https://toscode.gitee.com/li_ziheng/lizhengi-samples/tree/feature%2Fspring-boot-1.0.1/ ~ 本篇内容包括:项目介绍与条件准备、项目搭建与构造、效果验证


文章目录


一、项目介绍与条件准备

1、项目使用框架/模块介绍

  • MapStruct:一个代码生成器,它基于约定优于配置方法极大地简化了 Java bean 类型之间映射的实现。自动生成的映射转换代码只使用简单的方法调用,因此速度快、类型安全而且易于理解阅读;
  • commons-lang3:apache 提供的众多 commons 工具包,号称 Java 第二 API,而 common 里面 lang3 包更是被我们使用得最多的。

2、MapStruct 注释说明

注解说明:

@Mapper 只有在接口加上这个注解, MapStruct 才会去实现该接口
    @Mapper 里有个 componentModel 属性,主要是指定实现类的类型,一般用到两个
    default:默认,可以通过 Mappers.getMapper(Class) 方式获取实例对象
    spring:在接口的实现类上自动添加注解 @Component,可通过 @Autowired 方式注入
@Mapping:属性映射,若源对象属性与目标对象名字一致,会自动映射对应属性
    source:源属性
    target:目标属性
    dateFormat:String 到 Date 日期之间相互转换,通过 SimpleDateFormat,该值为 SimpleDateFormat 的日期格式
    ignore: 忽略这个字段
@Mappings:配置多个@Mapping
@MappingTarget 用于更新已有对象
@InheritConfiguration 用于继承配置

3、Idea 安装 MapStruct 插件

Idea 可以安装以下 MapStruct 插件:

3、项目结构说明

├── controller — 控制层(将请求通过 url 匹配,分配到不同的接收器/方法进行处理,然后返回结果)

├── service — 服务层接口

​ └── impl — 服务层实现

├── mapper — 数据访问层,与数据库交互为 service 提供接口

├── entity — 实体对象

​ ├── converter — 实体对象转换器

​ ├── dto — 持久层需要的实体对象(用于服务层与持久层之间的数据传输对象)

​ └── vo — 视图层需要的实体对象(用于服务层与视图层之间的数据传输对象)

├── utils — 工具类

└── Application.java — 入口启动类


二、项目搭建与构造

1、添加项目 maven 依赖

# 添加项目 maven 依赖,pom.xml 文件添加内容如下:

        <!--    数据类型转化工具 MapStruct    -->
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-jdk8</artifactId>
            <version>1.3.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.3.0.Final</version>
        </dependency>
        
        <!--    apache的 common-lang3 工具类    -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>

2、转换对象 DTO 与 VO

# DTO对象 Event-事件 持久层实体对象实现

package com.lizhengi.entity.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * @author lizhengi
 * @version 1.0.0
 * @description Event-事件 持久层实体对象实现
 * @date 2022-12-07 3:59 下午
 **/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EventDTO {

    /**
     * 事件ID
     */
    private Integer eventId;

    /**
     * 事件名称
     */
    private String eventName;

    /**
     * 事件类型
     */
    private String eventType;

    /**
     * 事件发生是否为精确时间 0大约/1精确
     */
    private Boolean eventIsAccurate;

    /**
     * 事件发生在公元前 0公元前/公元后
     */
    private Boolean eventIsBc;

    /**
     * 事件发生年份
     */
    private String eventYear;

    /**
     * 事件发生月份
     */
    private String eventMonth;

    /**
     * 事件发生日
     */
    private String eventDay;

    /**
     * 事件地点
     */
    private String eventLocation;

    /**
     * 事件人物
     *
     * @see CharacterDTO
     */
    private List<CharacterDTO> eventCharacters;

    /**
     * 事件描述
     */
    private String eventDescription;
}

# DTO对象 Character-人物 持久层实体对象实现

package com.lizhengi.entity.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author lizhengi
 * @version 1.0.0
 * @description Character-人物 持久层实体对象实现
 * @date 2022-12-07 4:40 下午
 **/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CharacterDTO {

    /**
     * 人物ID
     */
    private Integer characterId;

    /**
     * 人物名称
     */
    private String characterName;

    /**
     * 人物介绍
     */
    private String characterProfile;

    /**
     * 人物登场时间(负数表示公元前)
     */
    private Integer characterAppearanceDate;
}

# VO对象 Event-事件 视图层实体对象实现

package com.lizhengi.entity.vo;

import com.lizhengi.entity.dto.CharacterDTO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * @author liziheng
 * @version 1.0.0
 * @description Event-事件 视图层实体对象实现
 * @date 2022-12-09 00:58 上午
 **/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EventVO {

    /**
     * 事件名称
     */
    private String eventName;

    /**
     * 事件类型
     */
    private String eventType;

    /**
     * 事件发生时间
     */
    private String eventDate;

    /**
     * 事件地点
     */
    private String eventLocation;

    /**
     * 事件人物
     *
     * @see CharacterDTO
     */
    private List<CharacterVO> characters;

    /**
     * 事件描述
     */
    private String eventDescription;
}

# VO对象 Character-人物 视图层实体对象实现

package com.lizhengi.entity.vo;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author liziheng
 * @version 1.0.0
 * @description Character-人物 视图层实体对象实现
 * @date 2022-12-09 00:59 上午
 **/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CharacterVO {

    /**
     * 人物名称
     */
    private String name;

    /**
     * 人物介绍
     */
    private String profile;

    /**
     * 人物登场时间(负数表示公元前)
     */
    private Integer appearanceDate;
}

3、转换器 Converter 实现

# EventConverter抽象类 Event-事件 转换器

package com.lizhengi.entity.converter;

import com.lizhengi.entity.dto.EventDTO;
import com.lizhengi.entity.vo.EventVO;
import com.lizhengi.utils.DateUtil;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author liziheng
 * @version 1.0.0
 * @description Event-事件 转换器
 * @date 2022-12-09 1:01 上午
 **/
@Mapper(componentModel = "Spring")
public abstract class EventConverter {

    @Resource
    CharacterConverter characterConverter;

    /**
     * DTO 转 VO
     *
     * @param eventDTO EventDTO
     * @return EventVO
     */
    @Mappings({
            @Mapping(target = "eventDate", expression = "java(dto2voFieldEventDateConverter(eventDTO))"),
            @Mapping(target = "characters", expression = "java(characterConverter.dtoList2voList(eventDTO.getEventCharacters()))")
    })
    public abstract EventVO dto2vo(EventDTO eventDTO);

    /**
     * DTO 列表 转 VO 列表
     *
     * @param eventDTOList List<EventDTO>
     * @return List<EventVO>
     */
    public abstract List<EventVO> dtoList2voList(List<EventDTO> eventDTOList);

    /**
     * DTO 与 VO 间时间类型转换
     * @param eventDTO EventDTO
     * @return String
     */
    public String dto2voFieldEventDateConverter(EventDTO eventDTO) {
        return DateUtil.getEventDateByDateInfo(eventDTO.getEventIsAccurate(), eventDTO.getEventIsBc(),
                eventDTO.getEventYear(), eventDTO.getEventMonth(), eventDTO.getEventDay());
    }
}

# CharacterConverter接口 Character-人物 转换器

package com.lizhengi.entity.converter;

import com.lizhengi.entity.dto.CharacterDTO;
import com.lizhengi.entity.vo.CharacterVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;

import java.util.List;

/**
 * @author liziheng
 * @version 1.0.0 
 * @description Character-人物 转换器
 * @date 2022-12-09 2:27 上午
 **/
@Mapper(componentModel = "Spring")
public interface CharacterConverter {

    /**
     * DTO 转 VO
     *
     * @param characterDTO characterDTO
     * @return characterVO
     */
    @Mappings({
            @Mapping(target = "appearanceDate", source = "characterAppearanceDate"),
            @Mapping(target = "name", source = "characterName"),
            @Mapping(target = "profile", source = "characterProfile")
    })
    CharacterVO dto2vo(CharacterDTO characterDTO);

    /**
     * DTO 列表 转 VO 列表
     *
     * @param characterDTOList List<characterDTO>
     * @return List<characterVO>
     */
    List<CharacterVO> dtoList2voList(List<CharacterDTO> characterDTOList);
}

4、相关工具类实现

# 日期工具类

package com.lizhengi.utils;

import org.apache.commons.lang3.StringUtils;

/**
 * @author liziheng
 * @version 1.0.0
 * @description 日期工具类
 * @date 2022-12-09 2:20 上午
 **/
public class DateUtil {


    /**
     * 根据「事件时间信息」获取「事件时间概述」
     *
     * @param isAccurate 是否精确时间
     * @param isBc       是否为公元前
     * @param year       年份
     * @param month      月份
     * @param day        日
     * @return String
     */
    public static String getEventDateByDateInfo(Boolean isAccurate, Boolean isBc, String year, String month, String day) {

        StringBuilder builder = new StringBuilder();

        if (!isAccurate) {
            builder.append("约");
        }
        if (isBc) {
            builder.append("公元前");
        } else {
            builder.append("公元");
        }
        // 具体日期
        builder.append(year).append("年")
                .append(StringUtils.isBlank(month) ? "" : (month + "月"))
                .append((StringUtils.isBlank(month) || StringUtils.isBlank(day) ? "" : day + "日"));
        return String.valueOf(builder);
    }
}

5、service 服务层调用

# EventServiceImpl Event-事件 ServiceImpl

package com.lizhengi.service.impl;

import com.lizhengi.entity.converter.EventConverter;
import com.lizhengi.entity.vo.EventVO;
import com.lizhengi.mapper.EventMapper;
import com.lizhengi.service.EventService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author lizhengi
 * @version 1.0.0
 * @description Event-事件 ServiceImpl
 * @date 2022-12-07 8:14 下午
 **/
@Service
public class EventServiceImpl implements EventService {

    EventMapper mapper;

    @Autowired
    public void setMapper(EventMapper mapper) {
        this.mapper = mapper;
    }

    @Resource
    private EventConverter eventConverter;

    /**
     * 全量获取 EventDto 信息
     *
     * @return List<EventDTO>
     */
    @Override
    public List<EventVO> getEventDtoList(){
        // 使用 MapStruct 实现 DTO-VO 转换器
        return eventConverter.dtoList2voList(mapper.getEventDtoList());
    }

}

6、controller 控制层实现

# EventController

package com.lizhengi.controller;

import com.lizhengi.entity.vo.EventVO;
import com.lizhengi.service.impl.EventServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @author liziheng
 * @version 1.0.0
 * @description Event-事件 Controller
 * @date 2022-12-07 8:17 下午
 **/
@RestController
@RequestMapping("/api/lizhengi/event")
public class EventController {

    EventServiceImpl eventService;

    @Autowired
    public void setEventService(EventServiceImpl eventService) {
        this.eventService = eventService;
    }

    @RequestMapping(path = {"/list"}, method = RequestMethod.GET)
    public List<EventVO> getEventDtoList(){
        return eventService.getEventDtoList();
    }

}

三、效果验证

使用 Postman 请求 ‘http://localhost:8080/api/lizhengi/event/list’ 接口,验证效果: