摘要:商品類型實體恒宇少年碼云商品基本信息實體恒宇少年碼云接下來我們繼續創建相關的。注解是用于標注接口抽象類是被自動映射的標識,只有存在該注解才會將內部的接口方法自動實現。
MapStruct是一種類型安全的bean映射類生成java注釋處理器。
我們要做的就是定義一個映射器接口,聲明任何必需的映射方法。在編譯的過程中,MapStruct會生成此接口的實現。該實現使用純java方法調用的源和目標對象之間的映射,MapStruct節省了時間,通過生成代碼完成繁瑣和容易出錯的代碼邏輯。下面我們來揭開它的神秘面紗
基于SpringBoot平臺完成MapStruct映射框架的集成。
構建項目我們使用idea開發工具創建一個SpringBoot項目,添加相應的依賴,pom.xml配置文件如下所示:
...省略部分代碼org.springframework.boot spring-boot-starter-parent 1.5.6.RELEASE UTF-8 UTF-8 1.8 1.2.0.CR1 ....省略部分代碼 org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-web mysql mysql-connector-java runtime org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-test test org.mapstruct mapstruct-jdk8 ${org.mapstruct.version} org.mapstruct mapstruct-processor ${org.mapstruct.version} provided javax.inject javax.inject 1 com.alibaba druid 1.0.31 org.projectlombok lombok
集成MapStruct官方提供了兩種方式,上面配置文件內我們采用的是直接添加Maven依賴,而官方文檔還提供了另外一種方式,采用Maven插件形式配置,配置如下所示:
...引用官方文檔 ...... 1.2.0.CR1 ... org.mapstruct mapstruct-jdk8 ${org.mapstruct.version} ... org.apache.maven.plugins maven-compiler-plugin 3.5.1 1.8 org.mapstruct mapstruct-processor ${org.mapstruct.version}
我個人比較喜歡采用第一種方式,不需要配置過多的插件,依賴方式比較方便。
接下來我們開始配置下數據庫連接信息以及簡單的兩張表的SpringDataJPA相關接口。
在resource下新創建一個application.yml文件,并添加如下數據庫連接配置:
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8 username: root password: 123456 #最大活躍數 maxActive: 20 #初始化數量 initialSize: 1 #最大連接等待超時時間 maxWait: 60000 #打開PSCache,并且指定每個連接PSCache的大小 poolPreparedStatements: true maxPoolPreparedStatementPerConnectionSize: 20 #通過connectionProperties屬性來打開mergeSql功能;慢SQL記錄 #connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 minIdle: 1 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: select 1 from dual testWhileIdle: true testOnBorrow: false testOnReturn: false #配置監控統計攔截的filters,去掉后監控界面sql將無法統計,"wall"用于防火墻 filters: stat, wall, log4j jpa: properties: hibernate: show_sql: true format_sql: true
有關SpringDataJPA相關的學習請訪問第三章:SpringBoot使用SpringDataJPA完成CRUD,我們在數據庫內創建兩張表信息分別是商品基本信息表、商品類型表。
兩張表有相應的關聯,我們在不采用連接查詢的方式模擬使用MapStruct,表信息如下所示:
--商品類型信息表 CREATE TABLE `good_types` ( `tgt_id` int(11) NOT NULL AUTO_INCREMENT, `tgt_name` varchar(30) DEFAULT NULL, `tgt_is_show` int(1) DEFAULT NULL, `tgt_order` int(255) DEFAULT NULL, PRIMARY KEY (`tgt_id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; --商品基本信息表 CREATE TABLE `good_infos` ( `tg_id` int(11) NOT NULL AUTO_INCREMENT, `tg_type_id` int(11) DEFAULT NULL, `tg_title` varchar(30) DEFAULT NULL, `tg_price` decimal(8,2) DEFAULT NULL, `tg_order` int(2) DEFAULT NULL, PRIMARY KEY (`tg_id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; INSERT INTO `good_types` VALUES ("1", "青菜", "1", "1"); INSERT INTO `good_infos` VALUES ("1", "1", "芹菜", "12.40", "1");
下面我們根據這兩張表創建對應的實體類。
商品類型實體package com.yuqiyu.chapter30.bean; import lombok.Data; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; /** * ======================== * Created with IntelliJ IDEA. * User:恒宇少年 * Date:2017/8/20 * Time:11:17 * 碼云:http://git.oschina.net/jnyqy * ======================== */ @Entity @Table(name = "good_types") @Data public class GoodTypeBean { @Id @Column(name = "tgt_id") private Long id; @Column(name = "tgt_name") private String name; @Column(name = "tgt_is_show") private int show; @Column(name = "tgt_order") private int order; }商品基本信息實體
package com.yuqiyu.chapter30.bean; import lombok.Data; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; /** * ======================== * Created with IntelliJ IDEA. * User:恒宇少年 * Date:2017/8/20 * Time:11:16 * 碼云:http://git.oschina.net/jnyqy * ======================== */ @Entity @Table(name = "good_infos") @Data public class GoodInfoBean { @Id @Column(name = "tg_id") private Long id; @Column(name = "tg_title") private String title; @Column(name = "tg_price") private double price; @Column(name = "tg_order") private int order; @Column(name = "tg_type_id") private Long typeId; }
接下來我們繼續創建相關的JPA。
商品類型JPApackage com.yuqiyu.chapter30.jpa; import com.yuqiyu.chapter30.bean.GoodTypeBean; import org.springframework.data.jpa.repository.JpaRepository; /** * ======================== * Created with IntelliJ IDEA. * User:恒宇少年 * Date:2017/8/20 * Time:11:24 * 碼云:http://git.oschina.net/jnyqy * ======================== */ public interface GoodTypeJPA extends JpaRepository商品信息JPA{ }
package com.yuqiyu.chapter30.jpa; import com.yuqiyu.chapter30.bean.GoodInfoBean; import org.springframework.data.jpa.repository.JpaRepository; /** * ======================== * Created with IntelliJ IDEA. * User:恒宇少年 * Date:2017/8/20 * Time:11:23 * 碼云:http://git.oschina.net/jnyqy * ======================== */ public interface GoodInfoJPA extends JpaRepository配置MapStruct{ }
到目前為止我們的準備工作差不多完成了,下面我們開始配置使用MapStruct。我們的最終目的是為了返回一個自定義的DTO實體,那么我們就先來創建這個DTO,DTO的代碼如下所示:
package com.yuqiyu.chapter30.dto; import lombok.Data; /** * 轉換Dto * ======================== * Created with IntelliJ IDEA. * User:恒宇少年 * Date:2017/8/20 * Time:11:25 * 碼云:http://git.oschina.net/jnyqy * ======================== */ @Data public class GoodInfoDTO { //商品編號 private String goodId; //商品名稱 private String goodName; //商品價格 private double goodPrice; //類型名稱 private String typeName; }
可以看到GoodInfoDTO實體內集成了商品信息、商品類型兩張表內的數據,對應查詢出信息后,我們需要使用MapStruct自動映射到GoodInfoDTO。
創建MapperMapper這個定義一般是被廣泛應用到MyBatis半自動化ORM框架上,而這里的Mapper跟Mybatis沒有關系。下面我們先來看下代碼,如下所示:
package com.yuqiyu.chapter30.mapper; import com.yuqiyu.chapter30.bean.GoodInfoBean; import com.yuqiyu.chapter30.bean.GoodTypeBean; import com.yuqiyu.chapter30.dto.GoodInfoDTO; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; /** * 配置映射 * ======================== * Created with IntelliJ IDEA. * User:恒宇少年 * Date:2017/8/20 * Time:11:26 * 碼云:http://git.oschina.net/jnyqy * ======================== */ @Mapper(componentModel = "spring") //@Mapper public interface GoodInfoMapper { //public static GoodInfoMapper MAPPER = Mappers.getMapper(GoodInfoMapper.class); @Mappings({ @Mapping(source = "type.name",target = "typeName"), @Mapping(source = "good.id",target = "goodId"), @Mapping(source = "good.title",target = "goodName"), @Mapping(source = "good.price",target = "goodPrice") }) public GoodInfoDTO from(GoodInfoBean good, GoodTypeBean type); }
可以看到GoodInfoMapper是一個接口的形式存在的,當然也可以是一個抽象類,如果你需要在轉換的時候才用個性化的定制的時候可以采用抽象類的方式,相應的代碼配置官方文檔已經聲明。
@Mapper注解是用于標注接口、抽象類是被MapStruct自動映射的標識,只有存在該注解才會將內部的接口方法自動實現。
MapStruct為我們提供了多種的獲取Mapper的方式,比較常用的兩種分別是
默認配置,我們不需要做過多的配置內容,獲取Mapper的方式就是采用Mappers通過動態工廠內部反射機制完成Mapper實現類的獲取。
默認方式獲取Mapper如下所示:
//Mapper接口內部定義 public static GoodInfoMapper MAPPER = Mappers.getMapper(GoodInfoMapper.class); //外部調用 GoodInfoMapper.MAPPER.from(goodBean,goodTypeBean);
Spring方式我們需要在@Mapper注解內添加componentModel屬性值,配置后在外部可以采用@Autowired方式注入Mapper實現類完成映射方法調用。
Spring方式獲取Mapper如下所示:
//注解配置 @Mapper(componentModel = "spring") //注入Mapper實現類 @Autowired private GoodInfoMapper goodInfoMapper; //調用 goodInfoMapper.from(goodBean,goodTypeBean);
在Mapper接口定義方法上面聲明了一系列的注解映射@Mapping以及@Mappings,那么這兩個注解是用來干什么工作的呢?
@Mapping注解我們用到了兩個屬性,分別是source、target
source代表的是映射接口方法內的參數名稱,如果是基本類型的參數,參數名可以直接作為source的內容,如果是實體類型,則可以采用實體參數名.字段名的方式作為source的內容,配置如上面GoodInfoMapper內容所示。
target代表的是映射到方法方法值內的字段名稱,配置如上面GoodInfoMapper所示。
查看Mapper實現下面我們執行maven compile命令,到target/generated-sources/annotations目錄下查看對應Mapper實現類,實現類代碼如下所示:
package com.yuqiyu.chapter30.mapper; import com.yuqiyu.chapter30.bean.GoodInfoBean; import com.yuqiyu.chapter30.bean.GoodTypeBean; import com.yuqiyu.chapter30.dto.GoodInfoDTO; import javax.annotation.Generated; import org.springframework.stereotype.Component; @Generated( value = "org.mapstruct.ap.MappingProcessor", date = "2017-08-20T12:52:52+0800", comments = "version: 1.2.0.CR1, compiler: javac, environment: Java 1.8.0_111 (Oracle Corporation)" ) @Component public class GoodInfoMapperImpl implements GoodInfoMapper { @Override public GoodInfoDTO from(GoodInfoBean good, GoodTypeBean type) { if ( good == null && type == null ) { return null; } GoodInfoDTO goodInfoDTO = new GoodInfoDTO(); if ( good != null ) { if ( good.getId() != null ) { goodInfoDTO.setGoodId( String.valueOf( good.getId() ) ); } goodInfoDTO.setGoodName( good.getTitle() ); goodInfoDTO.setGoodPrice( good.getPrice() ); } if ( type != null ) { goodInfoDTO.setTypeName( type.getName() ); } return goodInfoDTO; } }
MapStruct根據我們配置的@Mapping注解自動將source實體內的字段進行了調用target實體內字段的setXxx方法賦值,并且做出了一切參數驗證。
我們采用了Spring方式獲取Mapper,在自動生成的實現類上MapStruct為我們自動添加了@ComponentSpring聲明式注入注解配置。
下面我們來創建一個測試的Controller,用于訪問具體請求地址時查詢出商品的基本信息以及商品的類型后調用GoodInfoMapper.from(xxx,xxx)方法完成返回GoodInfoDTO實例。Controller代碼實現如下所示:
package com.yuqiyu.chapter30.controller; import com.yuqiyu.chapter30.bean.GoodInfoBean; import com.yuqiyu.chapter30.bean.GoodTypeBean; import com.yuqiyu.chapter30.dto.GoodInfoDTO; import com.yuqiyu.chapter30.jpa.GoodInfoJPA; import com.yuqiyu.chapter30.jpa.GoodTypeJPA; import com.yuqiyu.chapter30.mapper.GoodInfoMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * 測試控制器 * ======================== * Created with IntelliJ IDEA. * User:恒宇少年 * Date:2017/8/20 * Time:12:24 * 碼云:http://git.oschina.net/jnyqy * ======================== */ @RestController public class GoodInfoController { /** * 注入商品基本信息jpa */ @Autowired private GoodInfoJPA goodInfoJPA; /** * 注入商品類型jpa */ @Autowired private GoodTypeJPA goodTypeJPA; /** * 注入mapStruct轉換Mapper */ @Autowired private GoodInfoMapper goodInfoMapper; /** * 查詢商品詳情 * @param id * @return */ @RequestMapping(value = "/detail/{id}") public GoodInfoDTO detail(@PathVariable("id") Long id) { //查詢商品基本信息 GoodInfoBean goodInfoBean = goodInfoJPA.findOne(id); //查詢商品類型基本信息 GoodTypeBean typeBean = goodTypeJPA.findOne(goodInfoBean.getTypeId()); //返回轉換dto return goodInfoMapper.from(goodInfoBean,typeBean); } }
在Controller內我們注入了GoodInfoJPA、GoodTypeJPA以及GoodInfoMapper,在查詢商品詳情方法時做出了映射處理。接下來我們啟動項目訪問地址http://127.0.0.1:8080/detail/1查看界面輸出效果,如下所示:
{ goodId: "1", goodName: "芹菜", goodPrice: 12.4, typeName: "青菜" }
可以看到界面輸出了GoodInfoDTO內的所有字段內容,并且通過from方法將對應配置的target字段賦值。
總結本章主要講述了基于SpringBoot開發框架上集成MapStruct自動映射框架,完成模擬多表獲取數據后將某一些字段通過@Mapping配置自動映射到DTO實體實例指定的字段內。
MapStruct官方文檔地址:http://mapstruct.org/documentation/dev/reference/html/
本章代碼已經上傳到碼云:
網頁地址:http://git.oschina.net/jnyqy/lessons
Git地址:https://git.oschina.net/jnyqy/lessons.git
SpringBoot相關系列文章請訪問:目錄:SpringBoot學習目錄
QueryDSL相關系列文章請訪問:QueryDSL通用查詢框架學習目錄
SpringDataJPA相關系列文章請訪問:目錄:SpringDataJPA學習目錄
感謝閱讀!
歡迎加入QQ技術交流群,共同進步。
QQ技術交流群
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67660.html
摘要:聲明業務實體對象,數據傳輸對象。這種對象與對象之間的互相轉換,就需要有一個專門用來解決轉換問題的工具,畢竟每一個字段都會很麻煩。就是這樣的一個屬性映射工具,只需要定義一個接口,就會自動實現這個映射接口,避免了復雜繁瑣的映射實現。 聲明: 1、DO(業務實體對象),DTO(數據傳輸對象)。 2、我的代碼中用到了 Lombok ,不了解的可以自行了解一下,了解的忽略這條就好。 在一個成熟的...
摘要:簡介項目基于的前后端分離的管理系統,項目采用分模塊開發方式,權限控制采用,基于角色的訪問控制,支持數據字典數據權限管理前端菜單支持動態路由,另外還有其他的功能模塊日志管理代碼生成器系統監控云存儲管理系統工具等等。 簡介 項目基于 Spring Boot 2.1.0 、 Spring Data JPA、 Spring Security、Redis、Vue的前后端分離的管理系統,項目采用分...
摘要:打開,,選中,然后再選中,輸入項目的和,指定等配置,修改,打開項目,添加一些必要的目錄,最終項目框架目錄圖如下修改文件,指定各依賴和插件的版本等信息在標簽里面管理各依賴的版本號添加項目依賴管理依賴配置好之后,開始整合。 最近在回顧和總結一些技術,想到了把之前比較火的 SSM 框架重新搭建出來,作為一個小結,同時也希望本文章寫出來能對大家有一些幫助和啟發,因本人水平有限,難免可能會有一些...
文章目錄 【微信開發】SpringBoot 集成微信小程序授權登錄1、SprinBoot 后端(1)準備工作(2)相關配置類(3)相關實體類(4)處理后端邏輯 2、Uniapp 前端(1)授權登錄(2)效果樣式 微信公眾號 【微信開發】SpringBoot 集成微信小程序授權登錄 我這里采用了第三方的依賴,目前是最火的微信開發工具吧,WxJava 1、SprinBoot 后端 (1)準備...
摘要:如何修改代碼為了盡量減少程序員的工作,我們的代碼生成器在生成完后,還需要將方法的返回值自動修改成這個類。具體的實現到此為止,基本上代碼生成器的主要障礙都有了相應的處理辦法。 當前的狀況 一般做數據庫相關開發, 除非學習, 否則很少有人愿意直接使用JDBC。本來Java代碼就比較啰嗦了,而直接用JDBC寫代碼之啰嗦簡直有些令人發狂!所以在實際開發過程中,我們通常都會使用一些框架/庫來幫助...
閱讀 3098·2023-04-26 01:58
閱讀 951·2021-11-24 09:38
閱讀 3285·2021-09-03 10:29
閱讀 713·2021-08-21 14:10
閱讀 1488·2019-08-30 15:44
閱讀 3085·2019-08-30 14:10
閱讀 3211·2019-08-29 16:32
閱讀 1476·2019-08-29 12:48