在之前章節的例子中,我們在接收參數的時候都是使用的 User 類對象,這是一個 DO 對象,
但是這個對象與前端業務通常不能對等,所以更多時候,會創建一個 BO 類用來接收入參。
那麼這時就會涉及到 BO 屬性值複製至 DO,然後代碼裏就會出現大量的 do.set(bo.get())
,
這時,對反射比較瞭解的同學應該就會嘗試使用反射來解決這個問題,雖然可以解決問題,但是反射會降低程序性能,
而 MapStruct 則是另外一種解決方案。
相關知識
MapStruct官網:http://mapstruct.org
目標
整合 MapStruce 以及 Lombok
準備工作
- Idea 集成開發環境
安裝 MapStruct 插件
File -> settings,打開 Idea 的設置界面,從左側欄選擇 Plugins 選項,再在右側查詢 MapStruce,點擊安裝。
設置
File -> Settings 打開設置界面,
選擇 Build,Execution,Deployment -> Compiler -> Annotation Processors 進入設置界面,
勾選 enable annotation processing
操作步驟
添加依賴
引入 Spring Boot Starter 父工程
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
添加 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>
<scope>provided</scope>
</dependency>
添加 mapstruct
及 lombok
的插件依賴
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.0.Final</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
整體依賴如下
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<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>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.0.Final</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
編碼
- BO 層代碼,用於接收前端入參
@Getter
@Setter
public class UserBO {
private String mobile;
private String upwd;
}
- MapStruct 接口
- 類上添加
@Mapper
註解,項目編譯時,MapStruct 將自動爲該接口生成實現類 - 方法上添加
@Mapping
註解,用於設置規則 - 設置常量
INSTANCE
,供其它類調用,也可以通過 Spring 的 IOC 進行注入
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
@Mapping(source = "mobile", target = "name")
User bo2Do(UserBO bo);
}
- Controller 層代碼
@RestController
@Slf4j
@AllArgsConstructor
public class UserController {
@PostMapping("/register")
public User register(@RequestBody UserBO userBo) {
User user = UserMapper.INSTANCE.bo2Do(userBo);
// ... 執行數據庫操作
return user;
}
}
- 啓動類
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
驗證結果
測試用例
@RunWith(SpringRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = Application.class)
public class UserTest {
private MockMvc mvc;
@Autowired
private WebApplicationContext webApplicationContext;
@Before
public void setUp() {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void test1() throws Exception {
MvcResult mvcResult = mvc.perform(
MockMvcRequestBuilders
.post("/register")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content("{\"mobile\":\"13700000001\",\"upwd\":\"123456\"}")
)
.andDo(MockMvcResultHandlers.print())
.andReturn();
Assert.assertEquals(200, mvcResult.getResponse().getStatus());
}
}
輸出如下
{"id":null,"name":"13700000001","sex":null,"birthday":null,"level":null}
編譯項目
在項目的 target 子目錄下可以找到 UserMapperImpl.class 文件,這個就是 MapStruct 在編譯期自動生成實現類
public class UserMapperImpl implements UserMapper {
public UserMapperImpl() {
}
public User bo2Do(UserBO bo) {
if (bo == null) {
return null;
} else {
User user = new User();
user.setName(bo.getMobile());
return user;
}
}
}
源碼地址
本章源碼 : https://gitee.com/gongm_24/spring-boot-tutorial.git
結束語
MapStruct 釋放掉大量的屬性複製的代碼,改爲編譯期自動生成,精簡了項目代碼同時也保證了高性能