MapStruct 是一个代码生成器,它基于约定优于配置方法极大地简化了 Java bean 类型之间映射的实现。自动生成的映射转换代码只使用简单的方法调用,因此速度快、类型安全而且易于理解阅读;本篇就是实现 SpringBoot 整合 MapStruct 实现数据类型转化。 项目源码实现前分支地址:https://toscode.gitee.com/li_ziheng/lizhengi-samples/tree/feature/spring-boot-1.0.0/ 项目源码实现后分支地址:https://toscode.gitee.com/li_ziheng/lizhengi-samples/tree/feature/spring-boot-1.0.1/ ~ 本篇内容包括:项目介绍与条件准备、项目搭建与构造、效果验证
文章目录- 一、项目介绍与条件准备
- 1、项目使用框架/模块介绍
- 2、MapStruct 注释说明
- 3、Idea 安装 MapStruct 插件
- 3、项目结构说明
- 1、项目使用框架/模块介绍
- 2、MapStruct 注释说明
- 3、Idea 安装 MapStruct 插件
- 3、项目结构说明
- 二、项目搭建与构造
- 1、添加项目 maven 依赖
- 2、转换对象 DTO 与 VO
- 3、转换器 Converter 实现
- 4、相关工具类实现
- 5、service 服务层调用
- 6、controller 控制层实现
- 三、效果验证
一、项目介绍与条件准备
1、项目使用框架/模块介绍
- MapStruct:一个代码生成器,它基于约定优于配置方法极大地简化了 Java bean 类型之间映射的实现。自动生成的映射转换代码只使用简单的方法调用,因此速度快、类型安全而且易于理解阅读;
- commons-lang3:apache 提供的众多 commons 工具包,号称 Java 第二 API,而 common 里面 lang3 包更是被我们使用得最多的。
2、MapStruct 注释说明
注解说明:
代码语言:javascript复制@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 文件添加内容如下:
代码语言:javascript复制 <!-- 数据类型转化工具 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-事件 持久层实体对象实现
代码语言:javascript复制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-人物 持久层实体对象实现
代码语言:javascript复制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-事件 视图层实体对象实现
代码语言:javascript复制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-人物 视图层实体对象实现
代码语言:javascript复制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-事件 转换器
代码语言:javascript复制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-人物 转换器
代码语言:javascript复制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、相关工具类实现
# 日期工具类
代码语言:javascript复制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
代码语言:javascript复制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
代码语言:javascript复制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’ 接口,验证效果: