惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

美团技术团队
罗磊的独立博客
SecWiki News
SecWiki News
The Register - Security
The Register - Security
The GitHub Blog
The GitHub Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
S
Schneier on Security
IT之家
IT之家
博客园 - 聂微东
T
The Exploit Database - CXSecurity.com
Recorded Future
Recorded Future
大猫的无限游戏
大猫的无限游戏
Know Your Adversary
Know Your Adversary
Latest news
Latest news
Vercel News
Vercel News
G
GRAHAM CLULEY
D
DataBreaches.Net
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
SegmentFault 最新的问题
博客园_首页
雷峰网
雷峰网
T
Tenable Blog
Spread Privacy
Spread Privacy
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
酷 壳 – CoolShell
酷 壳 – CoolShell
Cisco Talos Blog
Cisco Talos Blog
V
Visual Studio Blog
J
Java Code Geeks
博客园 - Franky
The Cloudflare Blog
Apple Machine Learning Research
Apple Machine Learning Research
C
CERT Recently Published Vulnerability Notes
T
Threatpost
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
P
Privacy International News Feed
T
Threat Research - Cisco Blogs
T
The Blog of Author Tim Ferriss
V
Vulnerabilities – Threatpost
Recent Announcements
Recent Announcements
Blog — PlanetScale
Blog — PlanetScale
Security Latest
Security Latest
U
Unit 42
M
MIT News - Artificial intelligence
Y
Y Combinator Blog
K
Kaspersky official blog
有赞技术团队
有赞技术团队
B
Blog
腾讯CDC

博客园 - luckygxf

javascript构造方法 数据库连接池初始连接 分布式系统CAP理论(一) 数据库连接太多排查(一) 审批流程-节点自动审批通过 防表单重复提交 深分页问题 devops 对象存储迁移-组件上线 工作效率提升 新需求开发-重构老的逻辑 js析构赋值 框架的好处和不足 React框架Hello world 数据库表设计在哪个接口 需求实现-ddd四层架构实现 前端代码(一) 高内聚,低耦合 对象存储改造 mermaid初体验 业务逻辑优化-解决提示词问题打分不准 idea 插件envfile初体验 防盗链-防盗用链接 springboot项目启动小技巧 github托管网站 AI MCP开发 AI中 MCP 作用 架构积累-解耦与防腐 表创建索引的重要性 重构注意事项(一) drawio初体验 六边形架构 架构积累-依赖注入和SOLID原则 工作总结-定时任务 工作总结-知识通关需求上线 工作总结-演练场景映射方案 工作总结-MVP 工作总结-需要学习的方向 工作总结-接口优化 python asyncio demo 工作总结-sse接口心跳 工作总结-问题筛选方案 工作总结-工具分享 工作总结-提示词优化 工作总结-工作优先级 工作总结-灰度发布
mapconstruct 初体验
luckygxf · 2026-04-18 · via 博客园 - luckygxf

如果有两个两个实体对象,想把一个对象的字段值赋值给另一个对象。可以通过set/get方法直接设置,不过这样很多模板代码。太多了,不能很好的突出业务,我们主要精力还是要放在业务上。

可以通过spring的beanutil.copyproperities方法,设置对象字段值。不过这个有一些不是很好的地方

1.是通过反射实现的,虽然反射经过了一系列优化。速度和编译后的字节码直接调用,差距不是很大,应该还是要慢一些。我没有实际验证过

2.好像必须要类型、字段名,相同才能直接复制。如果字段名不相同,就不会复制,不够灵活

使用mapconstruct

1. 可以通过编译,直接赋值,不用反射。基于注解处理器,在编译的时候。生成mapper接口实现类,实现对象的赋值

2.可以指定源对象的字段,目标字段

下面是官网的一个demo,在本地跑了下,注意和lombok冲突,执行顺序。在跑官网demo的使用,觉得有两个地方比较好

1. 可以在pom定义变量,比如依赖的版本,可以在多个地方引用。类似代码重复常量,不使用硬编码,使用常量定义

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <lombok.version>1.18.20</lombok.version>
        <mapstruct.version>1.2.0.Final</mapstruct.version>
    </properties>

2.我们做测试,可能会在main方法写测试逻辑。main方法只有一个,只能写一个测试逻辑。我们可以使用单元测试,写多个测试逻辑。也可以不断沉淀,积累

public class CarMapperTest {
    @Test
    public void shouldMapCarToDto() {
        //given
        Car car = new Car( "Morris", 5);

        //when
        CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );

        //then
        System.out.println(carDto);
    }
}
public class StudentMapperTest {

    @Test
    public void test() {
        Student student = new Student(10, "zhangsan");
        StudentVo studentVo = StudentMapper.INSTANCE.studentVoToStudentVo(student);
        System.out.println(studentVo);
    }
}

官网demo

package com.gxf.po;

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

/**
 * @author guanxiangfei
 * @version 1.0.0
 * @since 2026/4/18
 */
//@AllArgsConstructor
//@NoArgsConstructor
//@Data
public class Car {

    private String make;
    private int numberOfSeats;
//    private CarType type;

    //constructor, getters, setters etc.


    public Car() {
    }

    public Car(String make, int numberOfSeats) {
        this.make = make;
        this.numberOfSeats = numberOfSeats;
    }

    public String getMake() {
        return make;
    }

    public void setMake(String make) {
        this.make = make;
    }

    public int getNumberOfSeats() {
        return numberOfSeats;
    }

    public void setNumberOfSeats(int numberOfSeats) {
        this.numberOfSeats = numberOfSeats;
    }

    @Override
    public String toString() {
        return "Car{" +
                "make='" + make + '\'' +
                ", numberOfSeats=" + numberOfSeats +
                '}';
    }
}
package com.gxf.dto;

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

/**
 * @author guanxiangfei
 * @version 1.0.0
 * @since 2026/4/18
 */
//@AllArgsConstructor
//@NoArgsConstructor
//@Data
public class CarDto {

    private String make;
    private int seatCount;
    private String type;

    //constructor, getters, setters etc.


    public CarDto() {
    }

    public CarDto(String make, int seatCount, String type) {
        this.make = make;
        this.seatCount = seatCount;
        this.type = type;
    }

    public String getMake() {
        return make;
    }

    public void setMake(String make) {
        this.make = make;
    }

    public int getSeatCount() {
        return seatCount;
    }

    public void setSeatCount(int seatCount) {
        this.seatCount = seatCount;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "CarDto{" +
                "make='" + make + '\'' +
                ", seatCount=" + seatCount +
                ", type='" + type + '\'' +
                '}';
    }
}
package com.gxf.mapper;

/**
 * @author guanxiangfei
 * @version 1.0.0
 * @since 2026/4/18
 */

import com.gxf.dto.CarDto;
import com.gxf.po.Car;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);
}