Atlas Mapper 案例 02:中级开发者 - 微服务架构用户中心

Java教程 2025-09-18

案例概述

用户画像

  • 角色:中级后端开发者
  • 姓名:张工
  • 工作经验:3-5 年
  • 技术背景:熟悉微服务架构、Spring Cloud、Redis、消息队列等
  • 所在公司:某大型互联网公司
  • 负责模块:用户中心微服务重构

业务背景

张工负责将公司的单体用户管理系统重构为微服务架构。系统需要支持多个业务线的用户数据需求,包括不同版本的 API、复杂的权限控制、以及高性能的数据处理。

面临的挑战

  1. 复杂的对象映射:用户实体包含多层嵌套关系(部门、角色、权限)
  2. 多版本 API 支持:需要同时支持 v1、v2 等多个版本的 API
  3. 权限敏感数据:根据用户权限动态决定返回哪些字段
  4. 高性能要求:支持大批量数据处理和缓存优化
  5. 微服务集成:多个服务间的数据传输标准化

️ 系统架构设计

微服务整体架构图

graph TB
    subgraph "用户中心微服务架构"
        subgraph "API Gateway"
            A[API 网关]
        end
        
        subgraph "用户中心服务"
            B[用户 Controller v1]
            C[用户 Controller v2]
            D[用户 Service]
            E[权限 Service]
            F[Atlas Mapper 层]
        end
        
        subgraph "数据层"
            G[用户 Repository]
            H[部门 Repository]
            I[角色 Repository]
            J[Redis 缓存]
            K[MySQL 数据库]
        end
        
        subgraph "其他微服务"
            L[订单服务]
            M[商品服务]
            N[消息服务]
        end
        
        subgraph "监控与治理"
            O[Prometheus]
            P[Jaeger 链路追踪]
            Q[ELK 日志]
        end
    end
    
    A --> B
    A --> C
    B --> D
    C --> D
    D --> E
    D --> F
    D --> G
    G --> H
    G --> I
    D --> J
    G --> K
    
    D --> L
    D --> M
    D --> N
    
    F --> O
    D --> P
    D --> Q

数据流程图

sequenceDiagram
    participant Client as 客户端
    participant Gateway as API网关
    participant UserController as 用户控制器
    participant UserService as 用户服务
    participant PermissionService as 权限服务
    participant UserMapper as 用户映射器
    participant Cache as Redis缓存
    participant UserRepo as 用户仓储
    participant DB as 数据库

    Client->>Gateway: GET /api/v2/users/{id}
    Gateway->>UserController: 路由请求
    UserController->>UserService: getUserV2(id, context)
    
    UserService->>Cache: 检查缓存
    alt 缓存命中
        Cache-->>UserService: 返回缓存数据
    else 缓存未命中
        UserService->>UserRepo: findByIdWithDetails(id)
        UserRepo->>DB: 查询用户详情
        DB-->>UserRepo: 用户实体数据
        UserRepo-->>UserService: User 对象
        UserService->>Cache: 缓存用户数据
    end
    
    UserService->>PermissionService: checkPermissions(context)
    PermissionService-->>UserService: 权限信息
    
    UserService->>UserMapper: toV2Dto(user, permissions)
    UserMapper-->>UserService: UserDtoV2
    
    UserService-->>UserController: UserDtoV2
    UserController-->>Gateway: JSON 响应
    Gateway-->>Client: 用户数据

映射策略架构图

graph TB
    subgraph "映射策略架构"
        A[用户实体 User] --> B[映射器选择器]
        
        B --> C[基础映射器]
        B --> D[V1 映射器]
        B --> E[V2 映射器]
        B --> F[管理员映射器]
        
        subgraph "权限控制"
            G[权限检查器]
            H[字段过滤器]
            I[敏感数据处理器]
        end
        
        C --> G
        D --> G
        E --> G
        F --> G
        
        G --> H
        H --> I
        
        I --> J[UserDto]
        I --> K[UserDtoV1]
        I --> L[UserDtoV2]
        I --> M[UserAdminDto]
        
        subgraph "性能优化"
            N[批量映射优化器]
            O[缓存策略]
            P[异步映射处理器]
        end
        
        B --> N
        N --> O
        O --> P
    end

需求分析

核心功能需求

1. 多版本 API 支持

V1 版本:基础用户信息

  • 用户 ID、用户名、邮箱、状态
  • 简单的日期格式化
  • 向后兼容性保证

V2 版本:增强用户信息

  • V1 所有字段 + 电话、最后登录时间
  • 用户资料信息(头像、性别等)
  • 部门名称和角色列表
  • 扩展字段支持

管理员版本:完整用户信息

  • 所有用户数据(包括敏感信息)
  • 完整的部门层级结构
  • 详细的角色权限信息
  • 扩展属性和元数据

2. 权限敏感数据处理

权限级别

  • 公开信息:用户名、头像等
  • 个人信息:邮箱、电话等(需要个人权限)
  • 敏感信息:身份证、银行卡等(需要管理员权限)
  • 系统信息:创建时间、IP 地址等(需要系统权限)

3. 高性能批量处理

性能要求

  • 单次映射 < 1ms
  • 批量映射(1000个)< 100ms
  • 内存使用优化,避免 OOM
  • 支持并发映射处理

4. 缓存集成策略

缓存层级

  • L1:本地缓存(映射结果)
  • L2:Redis 缓存(用户数据)
  • L3:数据库(持久化存储)

️ 实现方案

1. 复杂实体设计

/**
 * 用户实体 - 包含复杂的嵌套关系
 */
@Entity
@Table(name = "users")
@NamedEntityGraphs({
    @NamedEntityGraph(
        name = "User.withProfile",
        attributeNodes = @NamedAttributeNode("profile")
    ),
    @NamedEntityGraph(
        name = "User.withDepartmentAndRoles",
        attributeNodes = {
            @NamedAttributeNode(value = "department", subgraph = "department.parent"),
            @NamedAttributeNode("roles")
        },
        subgraphs = @NamedSubgraph(
            name = "department.parent",
            attributeNodes = @NamedAttributeNode("parent")
        )
    ),
    @NamedEntityGraph(
        name = "User.full",
        attributeNodes = {
            @NamedAttributeNode("profile"),
            @NamedAttributeNode(value = "department", subgraph = "department.full"),
            @NamedAttributeNode(value = "roles", subgraph = "roles.permissions")
        },
        subgraphs = {
            @NamedSubgraph(
                name = "department.full",
                attributeNodes = {
                    @NamedAttributeNode("parent"),
                    @NamedAttributeNode("children")
                }
            ),
            @NamedSubgraph(
                name = "roles.permissions",
                attributeNodes = @NamedAttributeNode("permissions")
            )
        }
    )
})
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "username", unique = true, nullable = false)
    private String username;
    
    @Column(name = "email", unique = true)
    private String email;
    
    @Column(name = "phone")
    private String phone;
    
    /**
     * 用户状态:0-禁用, 1-正常, 2-锁定, 3-待激活
     */
    @Column(name = "status")
    private Integer status;
    
    @Column(name = "create_time")
    private LocalDateTime createTime;
    
    @Column(name = "last_login_time")
    private LocalDateTime lastLoginTime;
    
    @Column(name = "login_count")
    private Long loginCount;
    
    /**
     * 用户资料(一对一关系)
     */
    @OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private UserProfile profile;
    
    /**
     * 所属部门(多对一关系)
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Department department;
    
    /**
     * 用户角色(多对多关系)
     */
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
        name = "user_roles",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id")
    )
    private Set roles = new HashSet<>();
    
    /**
     * 扩展属性(JSON 存储)
     */
    @Type(type = "json")
    @Column(name = "extended_attributes", columnDefinition = "json")
    private Map extendedAttributes = new HashMap<>();
    
    /**
     * 用户标签
     */
    @ElementCollection
    @CollectionTable(name = "user_tags", joinColumns = @JoinColumn(name = "user_id"))
    @Column(name = "tag")
    private Set tags = new HashSet<>();
    
    // 构造函数
    public User() {}
    
    public User(String username, String email, String phone) {
        this.username = username;
        this.email = email;
        this.phone = phone;
        this.status = 3; // 默认待激活
        this.createTime = LocalDateTime.now();
        this.loginCount = 0L;
    }
    
    // 业务方法
    public boolean isActive() {
        return status != null && status == 1;
    }
    
    public boolean isLocked() {
        return status != null && status == 2;
    }
    
    public void recordLogin() {
        this.lastLoginTime = LocalDateTime.now();
        this.loginCount = (this.loginCount == null ? 0 : this.loginCount) + 1;
    }
    
    public boolean hasRole(String roleName) {
        return roles.stream().anyMatch(role -> roleName.equals(role.getName()));
    }
    
    public boolean hasPermission(String permission) {
        return roles.stream()
            .flatMap(role -> role.getPermissions().stream())
            .anyMatch(perm -> permission.equals(perm.getName()));
    }
    
    // getter 和 setter 方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }
    
    public Integer getStatus() { return status; }
    public void setStatus(Integer status) { this.status = status; }
    
    public LocalDateTime getCreateTime() { return createTime; }
    public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
    
    public LocalDateTime getLastLoginTime() { return lastLoginTime; }
    public void setLastLoginTime(LocalDateTime lastLoginTime) { this.lastLoginTime = lastLoginTime; }
    
    public Long getLoginCount() { return loginCount; }
    public void setLoginCount(Long loginCount) { this.loginCount = loginCount; }
    
    public UserProfile getProfile() { return profile; }
    public void setProfile(UserProfile profile) { this.profile = profile; }
    
    public Department getDepartment() { return department; }
    public void setDepartment(Department department) { this.department = department; }
    
    public Set getRoles() { return roles; }
    public void setRoles(Set roles) { this.roles = roles; }
    
    public Map getExtendedAttributes() { return extendedAttributes; }
    public void setExtendedAttributes(Map extendedAttributes) { this.extendedAttributes = extendedAttributes; }
    
    public Set getTags() { return tags; }
    public void setTags(Set tags) { this.tags = tags; }
}

/**
 * 用户资料实体
 */
@Entity
@Table(name = "user_profiles")
public class UserProfile {
    @Id
    private Long userId;
    
    @Column(name = "real_name")
    private String realName;
    
    @Column(name = "avatar_url")
    private String avatarUrl;
    
    @Column(name = "gender")
    private String gender; // M-男, F-女, U-未知
    
    @Column(name = "birthday")
    private LocalDate birthday;
    
    @Column(name = "address")
    private String address;
    
    @Column(name = "bio", length = 500)
    private String bio;
    
    @Column(name = "website")
    private String website;
    
    /**
     * 敏感信息(需要特殊权限访问)
     */
    @Column(name = "id_card")
    private String idCard;
    
    @Column(name = "bank_card")
    private String bankCard;
    
    /**
     * 一对一关系
     */
    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    @JoinColumn(name = "user_id")
    private User user;
    
    // 构造函数
    public UserProfile() {}
    
    public UserProfile(User user, String realName) {
        this.user = user;
        this.userId = user.getId();
        this.realName = realName;
    }
    
    // 业务方法
    public String getDisplayName() {
        return realName != null ? realName : (user != null ? user.getUsername() : "未知用户");
    }
    
    public Integer getAge() {
        if (birthday == null) return null;
        return Period.between(birthday, LocalDate.now()).getYears();
    }
    
    public String getGenderDisplay() {
        if (gender == null) return "未知";
        switch (gender) {
            case "M": return "男";
            case "F": return "女";
            default: return "未知";
        }
    }
    
    // getter 和 setter 方法...
    public Long getUserId() { return userId; }
    public void setUserId(Long userId) { this.userId = userId; }
    
    public String getRealName() { return realName; }
    public void setRealName(String realName) { this.realName = realName; }
    
    public String getAvatarUrl() { return avatarUrl; }
    public void setAvatarUrl(String avatarUrl) { this.avatarUrl = avatarUrl; }
    
    public String getGender() { return gender; }
    public void setGender(String gender) { this.gender = gender; }
    
    public LocalDate getBirthday() { return birthday; }
    public void setBirthday(LocalDate birthday) { this.birthday = birthday; }
    
    public String getAddress() { return address; }
    public void setAddress(String address) { this.address = address; }
    
    public String getBio() { return bio; }
    public void setBio(String bio) { this.bio = bio; }
    
    public String getWebsite() { return website; }
    public void setWebsite(String website) { this.website = website; }
    
    public String getIdCard() { return idCard; }
    public void setIdCard(String idCard) { this.idCard = idCard; }
    
    public String getBankCard() { return bankCard; }
    public void setBankCard(String bankCard) { this.bankCard = bankCard; }
    
    public User getUser() { return user; }
    public void setUser(User user) { this.user = user; }
}

/**
 * 部门实体
 */
@Entity
@Table(name = "departments")
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "name", nullable = false)
    private String name;
    
    @Column(name = "code", unique = true)
    private String code;
    
    @Column(name = "description")
    private String description;
    
    @Column(name = "level")
    private Integer level;
    
    @Column(name = "sort_order")
    private Integer sortOrder;
    
    /**
     * 父部门(自关联)
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    private Department parent;
    
    /**
     * 子部门列表
     */
    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @OrderBy("sortOrder ASC")
    private List children = new ArrayList<>();
    
    /**
     * 部门用户
     */
    @OneToMany(mappedBy = "department", fetch = FetchType.LAZY)
    private List users = new ArrayList<>();
    
    // 构造函数
    public Department() {}
    
    public Department(String name, String code, Department parent) {
        this.name = name;
        this.code = code;
        this.parent = parent;
        this.level = parent != null ? parent.getLevel() + 1 : 1;
    }
    
    // 业务方法
    public String getFullPath() {
        if (parent == null) {
            return name;
        }
        return parent.getFullPath() + " > " + name;
    }
    
    public boolean isRoot() {
        return parent == null;
    }
    
    public boolean isLeaf() {
        return children.isEmpty();
    }
    
    // getter 和 setter 方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public String getCode() { return code; }
    public void setCode(String code) { this.code = code; }
    
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    
    public Integer getLevel() { return level; }
    public void setLevel(Integer level) { this.level = level; }
    
    public Integer getSortOrder() { return sortOrder; }
    public void setSortOrder(Integer sortOrder) { this.sortOrder = sortOrder; }
    
    public Department getParent() { return parent; }
    public void setParent(Department parent) { this.parent = parent; }
    
    public List getChildren() { return children; }
    public void setChildren(List children) { this.children = children; }
    
    public List getUsers() { return users; }
    public void setUsers(List users) { this.users = users; }
}

/**
 * 角色实体
 */
@Entity
@Table(name = "roles")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "name", unique = true, nullable = false)
    private String name;
    
    @Column(name = "display_name")
    private String displayName;
    
    @Column(name = "description")
    private String description;
    
    @Column(name = "is_system")
    private Boolean isSystem = false;
    
    /**
     * 角色权限(多对多关系)
     */
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
        name = "role_permissions",
        joinColumns = @JoinColumn(name = "role_id"),
        inverseJoinColumns = @JoinColumn(name = "permission_id")
    )
    private Set permissions = new HashSet<>();
    
    /**
     * 拥有此角色的用户
     */
    @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
    private Set users = new HashSet<>();
    
    // 构造函数
    public Role() {}
    
    public Role(String name, String displayName) {
        this.name = name;
        this.displayName = displayName;
    }
    
    // 业务方法
    public boolean hasPermission(String permissionName) {
        return permissions.stream().anyMatch(perm -> permissionName.equals(perm.getName()));
    }
    
    // getter 和 setter 方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public String getDisplayName() { return displayName; }
    public void setDisplayName(String displayName) { this.displayName = displayName; }
    
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    
    public Boolean getIsSystem() { return isSystem; }
    public void setIsSystem(Boolean isSystem) { this.isSystem = isSystem; }
    
    public Set getPermissions() { return permissions; }
    public void setPermissions(Set permissions) { this.permissions = permissions; }
    
    public Set getUsers() { return users; }
    public void setUsers(Set users) { this.users = users; }
}

/**
 * 权限实体
 */
@Entity
@Table(name = "permissions")
public class Permission {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "name", unique = true, nullable = false)
    private String name;
    
    @Column(name = "display_name")
    private String displayName;
    
    @Column(name = "description")
    private String description;
    
    @Column(name = "resource")
    private String resource;
    
    @Column(name = "action")
    private String action;
    
    // 构造函数
    public Permission() {}
    
    public Permission(String name, String displayName, String resource, String action) {
        this.name = name;
        this.displayName = displayName;
        this.resource = resource;
        this.action = action;
    }
    
    // getter 和 setter 方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public String getDisplayName() { return displayName; }
    public void setDisplayName(String displayName) { this.displayName = displayName; }
    
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    
    public String getResource() { return resource; }
    public void setResource(String resource) { this.resource = resource; }
    
    public String getAction() { return action; }
    public void setAction(String action) { this.action = action; }
}

2. 多版本 DTO 设计

/**
 * V1 版本用户 DTO - 基础信息
 */
public class UserDtoV1 {
    private Long id;
    private String username;
    private String email;
    private String status;
    private String createTime;
    
    // 构造函数
    public UserDtoV1() {}
    
    // getter 和 setter 方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }
    
    public String getCreateTime() { return createTime; }
    public void setCreateTime(String createTime) { this.createTime = createTime; }
}

/**
 * V2 版本用户 DTO - 增强信息
 */
public class UserDtoV2 {
    private Long id;
    private String username;
    private String email;
    private String phone;
    private String status;
    private String createTime;
    private String lastLoginTime;
    private Long loginCount;
    private UserProfileDto profile;
    private String departmentName;
    private String departmentPath;
    private List roleNames;
    private Set tags;
    
    // 构造函数
    public UserDtoV2() {}
    
    // getter 和 setter 方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }
    
    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }
    
    public String getCreateTime() { return createTime; }
    public void setCreateTime(String createTime) { this.createTime = createTime; }
    
    public String getLastLoginTime() { return lastLoginTime; }
    public void setLastLoginTime(String lastLoginTime) { this.lastLoginTime = lastLoginTime; }
    
    public Long getLoginCount() { return loginCount; }
    public void setLoginCount(Long loginCount) { this.loginCount = loginCount; }
    
    public UserProfileDto getProfile() { return profile; }
    public void setProfile(UserProfileDto profile) { this.profile = profile; }
    
    public String getDepartmentName() { return departmentName; }
    public void setDepartmentName(String departmentName) { this.departmentName = departmentName; }
    
    public String getDepartmentPath() { return departmentPath; }
    public void setDepartmentPath(String departmentPath) { this.departmentPath = departmentPath; }
    
    public List getRoleNames() { return roleNames; }
    public void setRoleNames(List roleNames) { this.roleNames = roleNames; }
    
    public Set getTags() { return tags; }
    public void setTags(Set tags) { this.tags = tags; }
}

/**
 * 管理员版本用户 DTO - 完整信息
 */
public class UserAdminDto {
    private Long id;
    private String username;
    private String email;
    private String phone;
    private String status;
    private String createTime;
    private String lastLoginTime;
    private Long loginCount;
    private UserProfileDto profile;
    private DepartmentDto department;
    private List roles;
    private Map extendedAttributes;
    private Set tags;
    
    // 敏感信息(仅管理员可见)
    private String lastLoginIp;
    private String registerIp;
    private Boolean isLocked;
    private String lockReason;
    
    // 构造函数
    public UserAdminDto() {}
    
    // getter 和 setter 方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }
    
    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }
    
    public String getCreateTime() { return createTime; }
    public void setCreateTime(String createTime) { this.createTime = createTime; }
    
    public String getLastLoginTime() { return lastLoginTime; }
    public void setLastLoginTime(String lastLoginTime) { this.lastLoginTime = lastLoginTime; }
    
    public Long getLoginCount() { return loginCount; }
    public void setLoginCount(Long loginCount) { this.loginCount = loginCount; }
    
    public UserProfileDto getProfile() { return profile; }
    public void setProfile(UserProfileDto profile) { this.profile = profile; }
    
    public DepartmentDto getDepartment() { return department; }
    public void setDepartment(DepartmentDto department) { this.department = department; }
    
    public List getRoles() { return roles; }
    public void setRoles(List roles) { this.roles = roles; }
    
    public Map getExtendedAttributes() { return extendedAttributes; }
    public void setExtendedAttributes(Map extendedAttributes) { this.extendedAttributes = extendedAttributes; }
    
    public Set getTags() { return tags; }
    public void setTags(Set tags) { this.tags = tags; }
    
    public String getLastLoginIp() { return lastLoginIp; }
    public void setLastLoginIp(String lastLoginIp) { this.lastLoginIp = lastLoginIp; }
    
    public String getRegisterIp() { return registerIp; }
    public void setRegisterIp(String registerIp) { this.registerIp = registerIp; }
    
    public Boolean getIsLocked() { return isLocked; }
    public void setIsLocked(Boolean isLocked) { this.isLocked = isLocked; }
    
    public String getLockReason() { return lockReason; }
    public void setLockReason(String lockReason) { this.lockReason = lockReason; }
}

/**
 * 用户资料 DTO
 */
public class UserProfileDto {
    private String realName;
    private String avatarUrl;
    private String gender;
    private String birthday;
    private Integer age;
    private String address;
    private String bio;
    private String website;
    
    // 敏感信息(根据权限决定是否包含)
    private String idCard;
    private String bankCard;
    
    // 构造函数
    public UserProfileDto() {}
    
    // getter 和 setter 方法...
    public String getRealName() { return realName; }
    public void setRealName(String realName) { this.realName = realName; }
    
    public String getAvatarUrl() { return avatarUrl; }
    public void setAvatarUrl(String avatarUrl) { this.avatarUrl = avatarUrl; }
    
    public String getGender() { return gender; }
    public void setGender(String gender) { this.gender = gender; }
    
    public String getBirthday() { return birthday; }
    public void setBirthday(String birthday) { this.birthday = birthday; }
    
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    
    public String getAddress() { return address; }
    public void setAddress(String address) { this.address = address; }
    
    public String getBio() { return bio; }
    public void setBio(String bio) { this.bio = bio; }
    
    public String getWebsite() { return website; }
    public void setWebsite(String website) { this.website = website; }
    
    public String getIdCard() { return idCard; }
    public void setIdCard(String idCard) { this.idCard = idCard; }
    
    public String getBankCard() { return bankCard; }
    public void setBankCard(String bankCard) { this.bankCard = bankCard; }
}

/**
 * 部门 DTO
 */
public class DepartmentDto {
    private Long id;
    private String name;
    private String code;
    private String description;
    private Integer level;
    private String fullPath;
    private DepartmentDto parent;
    private List children;
    
    // 构造函数
    public DepartmentDto() {}
    
    // getter 和 setter 方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public String getCode() { return code; }
    public void setCode(String code) { this.code = code; }
    
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    
    public Integer getLevel() { return level; }
    public void setLevel(Integer level) { this.level = level; }
    
    public String getFullPath() { return fullPath; }
    public void setFullPath(String fullPath) { this.fullPath = fullPath; }
    
    public DepartmentDto getParent() { return parent; }
    public void setParent(DepartmentDto parent) { this.parent = parent; }
    
    public List getChildren() { return children; }
    public void setChildren(List children) { this.children = children; }
}

/**
 * 角色 DTO
 */
public class RoleDto {
    private Long id;
    private String name;
    private String displayName;
    private String description;
    private Boolean isSystem;
    private List permissions;
    
    // 构造函数
    public RoleDto() {}
    
    // getter 和 setter 方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public String getDisplayName() { return displayName; }
    public void setDisplayName(String displayName) { this.displayName = displayName; }
    
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    
    public Boolean getIsSystem() { return isSystem; }
    public void setIsSystem(Boolean isSystem) { this.isSystem = isSystem; }
    
    public List getPermissions() { return permissions; }
    public void setPermissions(List permissions) { this.permissions = permissions; }
}

/**
 * 权限 DTO
 */
public class PermissionDto {
    private Long id;
    private String name;
    private String displayName;
    private String description;
    private String resource;
    private String action;
    
    // 构造函数
    public PermissionDto() {}
    
    // getter 和 setter 方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public String getDisplayName() { return displayName; }
    public void setDisplayName(String displayName) { this.displayName = displayName; }
    
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    
    public String getResource() { return resource; }
    public void setResource(String resource) { this.resource = resource; }
    
    public String getAction() { return action; }
    public void setAction(String action) { this.action = action; }
}

3. 高级映射器实现

/**
 * 用户映射器 - 支持多版本和权限控制
 */
@Mapper(
    componentModel = "spring",
    uses = {
        UserProfileMapper.class, 
        DepartmentMapper.class, 
        RoleMapper.class,
        PermissionMapper.class
    },
    unmappedTargetPolicy = ReportingPolicy.IGNORE,
    nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT,
    collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
    suppressGeneratorTimestamp = true,
    suppressGeneratorVersionComment = true
)
public interface UserMapper {
    
    /**
     * V1 版本映射 - 基础用户信息
     */
    @Mappings({
        @Mapping(target = "status", source = "status", qualifiedByName = "mapUserStatus"),
        @Mapping(target = "createTime", source = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss")
    })
    UserDtoV1 toV1Dto(User user);
    
    /**
     * V2 版本映射 - 增强用户信息
     */
    @Mappings({
        @Mapping(target = "status", source = "status", qualifiedByName = "mapUserStatus"),
        @Mapping(target = "createTime", source = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss"),
        @Mapping(target = "lastLoginTime", source = "lastLoginTime", dateFormat = "yyyy-MM-dd HH:mm:ss"),
        @Mapping(target = "departmentName", source = "department.name"),
        @Mapping(target = "departmentPath", source = "department", qualifiedByName = "getDepartmentPath"),
        @Mapping(target = "roleNames", source = "roles", qualifiedByName = "extractRoleNames")
    })
    UserDtoV2 toV2Dto(User user);
    
    /**
     * 管理员版本映射 - 完整用户信息
     */
    @Mappings({
        @Mapping(target = "status", source = "status", qualifiedByName = "mapUserStatus"),
        @Mapping(target = "createTime", source = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss"),
        @Mapping(target = "lastLoginTime", source = "lastLoginTime", dateFormat = "yyyy-MM-dd HH:mm:ss"),
        @Mapping(target = "extendedAttributes", source = "extendedAttributes", qualifiedByName = "mapExtendedAttributes"),
        @Mapping(target = "isLocked", source = "status", qualifiedByName = "isUserLocked")
    })
    UserAdminDto toAdminDto(User user);
    
    /**
     * 权限敏感映射 - 根据权限上下文决定返回内容
     */
    default UserDtoV2 toV2DtoWithPermissions(User user, SecurityContext context) {
        UserDtoV2 dto = toV2Dto(user);
        
        // 根据权限过滤敏感信息
        if (!context.hasPermission("USER:VIEW_PHONE")) {
            dto.setPhone(null);
        }
        
        if (!context.hasPermission("USER:VIEW_EMAIL")) {
            dto.setEmail(maskEmail(dto.getEmail()));
        }
        
        // 处理用户资料中的敏感信息
        if (dto.getProfile() != null) {
            filterProfileSensitiveData(dto.getProfile(), context);
        }
        
        return dto;
    }
    
    /**
     * 批量映射 - V1 版本
     */
    @IterableMapping(qualifiedByName = "toV1DtoOptimized")
    List toV1Dtos(List users);
    
    /**
     * 批量映射 - V2 版本
     */
    @IterableMapping(qualifiedByName = "toV2DtoOptimized")
    List toV2Dtos(List users);
    
    /**
     * 批量映射 - 管理员版本
     */
    List toAdminDtos(List users);
    
    /**
     * 双向映射 - DTO 转实体
     */
    @InheritInverseConfiguration(name = "toV2Dto")
    @Mappings({
        @Mapping(target = "id", ignore = true),
        @Mapping(target = "createTime", ignore = true),
        @Mapping(target = "lastLoginTime", ignore = true),
        @Mapping(target = "loginCount", ignore = true),
        @Mapping(target = "profile", ignore = true),
        @Mapping(target = "department", ignore = true),
        @Mapping(target = "roles", ignore = true),
        @Mapping(target = "extendedAttributes", ignore = true),
        @Mapping(target = "tags", ignore = true),
        @Mapping(target = "status", source = "status", qualifiedByName = "mapStringToStatus")
    })
    User fromV2Dto(UserDtoV2 dto);
    
    // ========== 自定义映射方法 ==========
    
    /**
     * 映射用户状态
     */
    @Named("mapUserStatus")
    default String mapUserStatus(Integer status) {
        if (status == null) return "未知";
        
        switch (status) {
            case 0: return "禁用";
            case 1: return "正常";
            case 2: return "锁定";
            case 3: return "待激活";
            default: return "未知";
        }
    }
    
    /**
     * 字符串状态转数字
     */
    @Named("mapStringToStatus")
    default Integer mapStringToStatus(String status) {
        if (status == null) return 0;
        
        switch (status) {
            case "禁用": return 0;
            case "正常": return 1;
            case "锁定": return 2;
            case "待激活": return 3;
            default: return 0;
        }
    }
    
    /**
     * 获取部门完整路径
     */
    @Named("getDepartmentPath")
    default String getDepartmentPath(Department department) {
        return department != null ? department.getFullPath() : "";
    }
    
    /**
     * 提取角色名称列表
     */
    @Named("extractRoleNames")
    default List extractRoleNames(Set roles) {
        if (roles == null || roles.isEmpty()) {
            return Collections.emptyList();
        }
        
        return roles.stream()
            .map(Role::getDisplayName)
            .filter(Objects::nonNull)
            .sorted()
            .collect(Collectors.toList());
    }
    
    /**
     * 映射扩展属性
     */
    @Named("mapExtendedAttributes")
    default Map mapExtendedAttributes(Map attributes) {
        if (attributes == null || attributes.isEmpty()) {
            return Collections.emptyMap();
        }
        
        return attributes.entrySet().stream()
            .filter(entry -> entry.getValue() != null)
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                entry -> convertToString(entry.getValue()),
                (existing, replacement) -> replacement,
                LinkedHashMap::new
            ));
    }
    
    /**
     * 判断用户是否被锁定
     */
    @Named("isUserLocked")
    default Boolean isUserLocked(Integer status) {
        return status != null && status == 2;
    }
    
    /**
     * 优化版本的 V1 映射
     */
    @Named("toV1DtoOptimized")
    default UserDtoV1 toV1DtoOptimized(User user) {
        if (user == null) return null;
        
        UserDtoV1 dto = new UserDtoV1();
        dto.setId(user.getId());
        dto.setUsername(user.getUsername());
        dto.setEmail(user.getEmail());
        dto.setStatus(mapUserStatus(user.getStatus()));
        dto.setCreateTime(formatDateTime(user.getCreateTime()));
        
        return dto;
    }
    
    /**
     * 优化版本的 V2 映射
     */
    @Named("toV2DtoOptimized")
    default UserDtoV2 toV2DtoOptimized(User user) {
        if (user == null) return null;
        
        UserDtoV2 dto = new UserDtoV2();
        dto.setId(user.getId());
        dto.setUsername(user.getUsername());
        dto.setEmail(user.getEmail());
        dto.setPhone(user.getPhone());
        dto.setStatus(mapUserStatus(user.getStatus()));
        dto.setCreateTime(formatDateTime(user.getCreateTime()));
        dto.setLastLoginTime(formatDateTime(user.getLastLoginTime()));
        dto.setLoginCount(user.getLoginCount());
        
        // 简化的部门信息
        if (user.getDepartment() != null) {
            dto.setDepartmentName(user.getDepartment().getName());
            dto.setDepartmentPath(user.getDepartment().getFullPath());
        }
        
        // 简化的角色信息
        dto.setRoleNames(extractRoleNames(user.getRoles()));
        dto.setTags(user.getTags());
        
        return dto;
    }
    
    // ========== 私有辅助方法 ==========
    
    /**
     * 格式化日期时间
     */
    default String formatDateTime(LocalDateTime dateTime) {
        if (dateTime == null) return null;
        return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }
    
    /**
     * 转换对象为字符串
     */
    default String convertToString(Object value) {
        if (value == null) return "";
        if (value instanceof String) return (String) value;
        if (value instanceof Number) return value.toString();
        if (value instanceof Boolean) return value.toString();
        if (value instanceof LocalDateTime) {
            return ((LocalDateTime) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        }
        if (value instanceof LocalDate) {
            return ((LocalDate) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }
        return value.toString();
    }
    
    /**
     * 邮箱脱敏
     */
    default String maskEmail(String email) {
        if (email == null || !email.contains("@")) return email;
        
        String[] parts = email.split("@");
        String username = parts[0];
        String domain = parts[1];
        
        if (username.length() <= 2) {
            return username + "@" + domain;
        }
        
        return username.charAt(0) + "***" + username.charAt(username.length() - 1) + "@" + domain;
    }
    
    /**
     * 过滤用户资料敏感数据
     */
    default void filterProfileSensitiveData(UserProfileDto profile, SecurityContext context) {
        if (!context.hasPermission("USER:VIEW_SENSITIVE")) {
            profile.setIdCard(null);
            profile.setBankCard(null);
        }
        
        if (!context.hasPermission("USER:VIEW_PERSONAL")) {
            profile.setBirthday(null);
            profile.setAge(null);
            profile.setAddress(null);
        }
    }
}

/**
 * 用户资料映射器
 */
@Mapper(
    componentModel = "spring",
    unmappedTargetPolicy = ReportingPolicy.IGNORE
)
public interface UserProfileMapper {
    
    @Mappings({
        @Mapping(target = "gender", source = "gender", qualifiedByName = "mapGenderDisplay"),
        @Mapping(target = "birthday", source = "birthday", dateFormat = "yyyy-MM-dd"),
        @Mapping(target = "age", source = "birthday", qualifiedByName = "calculateAge")
    })
    UserProfileDto toDto(UserProfile profile);
    
    @Named("mapGenderDisplay")
    default String mapGenderDisplay(String gender) {
        if (gender == null) return "未知";
        switch (gender) {
            case "M": return "男";
            case "F": return "女";
            default: return "未知";
        }
    }
    
    @Named("calculateAge")
    default Integer calculateAge(LocalDate birthday) {
        if (birthday == null) return null;
        return Period.between(birthday, LocalDate.now()).getYears();
    }
}

/**
 * 部门映射器
 */
@Mapper(
    componentModel = "spring",
    unmappedTargetPolicy = ReportingPolicy.IGNORE
)
public interface DepartmentMapper {
    
    @Mappings({
        @Mapping(target = "fullPath", source = ".", qualifiedByName = "getFullPath")
    })
    DepartmentDto toDto(Department department);
    
    List toDtos(List departments);
    
    @Named("getFullPath")
    default String getFullPath(Department department) {
        return department != null ? department.getFullPath() : "";
    }
}

/**
 * 角色映射器
 */
@Mapper(
    componentModel = "spring",
    uses = {PermissionMapper.class},
    unmappedTargetPolicy = ReportingPolicy.IGNORE
)
public interface RoleMapper {
    
    RoleDto toDto(Role role);
    
    List toDtos(List roles);
    
    Set toDtos(Set roles);
}

/**
 * 权限映射器
 */
@Mapper(
    componentModel = "spring",
    unmappedTargetPolicy = ReportingPolicy.IGNORE
)
public interface PermissionMapper {
    
    PermissionDto toDto(Permission permission);
    
    List toDtos(List permissions);
    
    Set toDtos(Set permissions);
}

4. 权限上下文和安全控制

/**
 * 安全上下文 - 用于权限控制
 */
public class SecurityContext {
    private Long userId;
    private String username;
    private Set roles;
    private Set permissions;
    private Map attributes;
    
    public SecurityContext(Long userId, String username) {
        this.userId = userId;
        this.username = username;
        this.roles = new HashSet<>();
        this.permissions = new HashSet<>();
        this.attributes = new HashMap<>();
    }
    
    /**
     * 检查是否拥有指定权限
     */
    public boolean hasPermission(String permission) {
        return permissions.contains(permission);
    }
    
    /**
     * 检查是否拥有指定角色
     */
    public boolean hasRole(String role) {
        return roles.contains(role);
    }
    
    /**
     * 检查是否拥有任一权限
     */
    public boolean hasAnyPermission(String... permissions) {
        return Arrays.stream(permissions).anyMatch(this::hasPermission);
    }
    
    /**
     * 检查是否拥有所有权限
     */
    public boolean hasAllPermissions(String... permissions) {
        return Arrays.stream(permissions).allMatch(this::hasPermission);
    }
    
    /**
     * 是否为管理员
     */
    public boolean isAdmin() {
        return hasRole("ADMIN") || hasRole("SUPER_ADMIN");
    }
    
    /**
     * 是否为系统用户
     */
    public boolean isSystem() {
        return hasRole("SYSTEM");
    }
    
    /**
     * 是否可以访问用户数据
     */
    public boolean canAccessUser(Long targetUserId) {
        // 自己的数据
        if (Objects.equals(userId, targetUserId)) {
            return true;
        }
        
        // 管理员权限
        if (isAdmin()) {
            return true;
        }
        
        // 特定权限
        return hasPermission("USER:VIEW_ALL");
    }
    
    // getter 和 setter 方法...
    public Long getUserId() { return userId; }
    public void setUserId(Long userId) { this.userId = userId; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public Set getRoles() { return roles; }
    public void setRoles(Set roles) { this.roles = roles; }
    
    public Set getPermissions() { return permissions; }
    public void setPermissions(Set permissions) { this.permissions = permissions; }
    
    public Map getAttributes() { return attributes; }
    public void setAttributes(Map attributes) { this.attributes = attributes; }
}

/**
 * 权限感知的用户映射器
 */
@Component
public class PermissionAwareUserMapper {
    
    private final UserMapper userMapper;
    
    public PermissionAwareUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
    
    /**
     * 根据权限上下文映射用户数据
     */
    public UserDtoV2 mapUserWithPermissions(User user, SecurityContext context) {
        // 检查基本访问权限
        if (!context.canAccessUser(user.getId())) {
            throw new AccessDeniedException("无权访问用户数据: " + user.getId());
        }
        
        // 根据权限级别选择映射策略
        if (context.isAdmin()) {
            // 管理员可以看到完整信息,但转换为 V2 格式
            UserAdminDto adminDto = userMapper.toAdminDto(user);
            return convertAdminToV2(adminDto);
        } else {
            // 普通用户使用权限过滤
            return userMapper.toV2DtoWithPermissions(user, context);
        }
    }
    
    /**
     * 批量映射用户数据(带权限控制)
     */
    public List mapUsersWithPermissions(List users, SecurityContext context) {
        return users.stream()
            .filter(user -> context.canAccessUser(user.getId()))
            .map(user -> mapUserWithPermissions(user, context))
            .collect(Collectors.toList());
    }
    
    /**
     * 根据权限级别选择映射版本
     */
    public Object mapUserByPermissionLevel(User user, SecurityContext context) {
        if (context.hasPermission("USER:VIEW_ADMIN")) {
            return userMapper.toAdminDto(user);
        } else if (context.hasPermission("USER:VIEW_DETAILED")) {
            return userMapper.toV2Dto(user);
        } else {
            return userMapper.toV1Dto(user);
        }
    }
    
    // 私有辅助方法
    private UserDtoV2 convertAdminToV2(UserAdminDto adminDto) {
        UserDtoV2 v2Dto = new UserDtoV2();
        v2Dto.setId(adminDto.getId());
        v2Dto.setUsername(adminDto.getUsername());
        v2Dto.setEmail(adminDto.getEmail());
        v2Dto.setPhone(adminDto.getPhone());
        v2Dto.setStatus(adminDto.getStatus());
        v2Dto.setCreateTime(adminDto.getCreateTime());
        v2Dto.setLastLoginTime(adminDto.getLastLoginTime());
        v2Dto.setLoginCount(adminDto.getLoginCount());
        v2Dto.setProfile(adminDto.getProfile());
        v2Dto.setTags(adminDto.getTags());
        
        // 转换部门信息
        if (adminDto.getDepartment() != null) {
            v2Dto.setDepartmentName(adminDto.getDepartment().getName());
            v2Dto.setDepartmentPath(adminDto.getDepartment().getFullPath());
        }
        
        // 转换角色信息
        if (adminDto.getRoles() != null) {
            v2Dto.setRoleNames(adminDto.getRoles().stream()
                .map(RoleDto::getDisplayName)
                .collect(Collectors.toList()));
        }
        
        return v2Dto;
    }
}

/**
 * 访问拒绝异常
 */
public class AccessDeniedException extends RuntimeException {
    public AccessDeniedException(String message) {
        super(message);
    }
}

性能优化实现

缓存策略和批量处理

/**
 * 高性能用户服务
 */
@Service
@Transactional(readOnly = true)
public class HighPerformanceUserService {
    
    private final UserRepository userRepository;
    private final PermissionAwareUserMapper userMapper;
    private final RedisTemplate redisTemplate;
    private final ThreadPoolTaskExecutor mappingExecutor;
    
    // 缓存配置
    private static final String USER_CACHE_PREFIX = "user:";
    private static final String USER_LIST_CACHE_PREFIX = "user:list:";
    private static final Duration CACHE_TTL = Duration.ofMinutes(30);
    
    public HighPerformanceUserService(
            UserRepository userRepository,
            PermissionAwareUserMapper userMapper,
            RedisTemplate redisTemplate,
            ThreadPoolTaskExecutor mappingExecutor) {
        this.userRepository = userRepository;
        this.userMapper = userMapper;
        this.redisTemplate = redisTemplate;
        this.mappingExecutor = mappingExecutor;
    }
    
    /**
     * 高性能用户查询(多级缓存)
     */
    @Cacheable(value = "users", key = "#id + ':' + #context.userId")
    public UserDtoV2 getUserById(Long id, SecurityContext context) {
        // L1: 检查本地缓存(由 @Cacheable 处理)
        
        // L2: 检查 Redis 缓存
        String cacheKey = USER_CACHE_PREFIX + id;
        User cachedUser = (User) redisTemplate.opsForValue().get(cacheKey);
        
        if (cachedUser != null) {
            return userMapper.mapUserWithPermissions(cachedUser, context);
        }
        
        // L3: 数据库查询
        User user = userRepository.findByIdWithFullDetails(id)
            .orElseThrow(() -> new UserNotFoundException("用户不存在: " + id));
        
        // 缓存到 Redis
        redisTemplate.opsForValue().set(cacheKey, user, CACHE_TTL);
        
        return userMapper.mapUserWithPermissions(user, context);
    }
    
    /**
     * 批量用户查询优化
     */
    public List getUsersByIds(List ids, SecurityContext context) {
        if (ids == null || ids.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 分批处理,避免内存溢出
        int batchSize = 100;
        List results = new ArrayList<>();
        
        for (int i = 0; i < ids.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, ids.size());
            List batchIds = ids.subList(i, endIndex);
            
            List batchResults = processBatchUsers(batchIds, context);
            results.addAll(batchResults);
        }
        
        return results;
    }
    
    /**
     * 异步批量映射
     */
    @Async("mappingExecutor")
    public CompletableFuture> getUsersAsync(
            List ids, SecurityContext context) {
        
        return CompletableFuture.supplyAsync(() -> {
            // 批量查询用户
            List users = userRepository.findAllByIdWithDetails(ids);
            
            // 并行映射
            return users.parallelStream()
                .map(user -> userMapper.mapUserWithPermissions(user, context))
                .collect(Collectors.toList());
        }, mappingExecutor);
    }
    
    /**
     * 智能分页查询
     */
    public Page getUsersWithSmartPaging(
            UserQueryCriteria criteria, Pageable pageable, SecurityContext context) {
        
        // 检查缓存
        String cacheKey = buildPageCacheKey(criteria, pageable, context);
        Page cachedPage = getCachedPage(cacheKey);
        
        if (cachedPage != null) {
            return cachedPage;
        }
        
        // 数据库查询
        Page userPage = userRepository.findByCriteriaWithDetails(criteria, pageable);
        
        // 根据数据量选择映射策略
        List userDtos;
        if (userPage.getContent().size() > 50) {
            // 大数据量使用并行映射
            userDtos = userPage.getContent().parallelStream()
                .map(user -> userMapper.mapUserWithPermissions(user, context))
                .collect(Collectors.toList());
        } else {
            // 小数据量使用串行映射
            userDtos = userPage.getContent().stream()
                .map(user -> userMapper.mapUserWithPermissions(user, context))
                .collect(Collectors.toList());
        }
        
        Page resultPage = new PageImpl<>(userDtos, pageable, userPage.getTotalElements());
        
        // 缓存结果
        cachePage(cacheKey, resultPage);
        
        return resultPage;
    }
    
    /**
     * 预热缓存
     */
    @EventListener(ApplicationReadyEvent.class)
    public void warmUpCache() {
        log.info("开始预热用户缓存...");
        
        CompletableFuture.runAsync(() -> {
            try {
                // 预热热点用户数据
                List hotUserIds = userRepository.findHotUserIds(100);
                List hotUsers = userRepository.findAllByIdWithDetails(hotUserIds);
                
                // 批量缓存
                Map cacheMap = hotUsers.stream()
                    .collect(Collectors.toMap(
                        user -> USER_CACHE_PREFIX + user.getId(),
                        user -> user
                    ));
                
                redisTemplate.opsForValue().multiSet(cacheMap);
                
                // 设置过期时间
                cacheMap.keySet().forEach(key -> 
                    redisTemplate.expire(key, CACHE_TTL));
                
                log.info("用户缓存预热完成,缓存了 {} 个用户", hotUsers.size());
                
            } catch (Exception e) {
                log.error("用户缓存预热失败", e);
            }
        }, mappingExecutor);
    }
    
    /**
     * 缓存失效处理
     */
    @EventListener
    public void handleUserUpdated(UserUpdatedEvent event) {
        Long userId = event.getUserId();
        
        // 清除相关缓存
        String userCacheKey = USER_CACHE_PREFIX + userId;
        redisTemplate.delete(userCacheKey);
        
        // 清除列表缓存(模糊匹配)
        Set listCacheKeys = redisTemplate.keys(USER_LIST_CACHE_PREFIX + "*");
        if (!listCacheKeys.isEmpty()) {
            redisTemplate.delete(listCacheKeys);
        }
        
        // 清除本地缓存
        evictLocalCache(userId);
        
        log.debug("用户缓存已清除: {}", userId);
    }
    
    // 私有辅助方法
    private List processBatchUsers(List batchIds, SecurityContext context) {
        // 先从缓存获取
        Map cachedUsers = getCachedUsers(batchIds);
        
        // 找出未缓存的 ID
        List uncachedIds = batchIds.stream()
            .filter(id -> !cachedUsers.containsKey(USER_CACHE_PREFIX + id))
            .collect(Collectors.toList());
        
        // 批量查询未缓存的用户
        if (!uncachedIds.isEmpty()) {
            List uncachedUsers = userRepository.findAllByIdWithDetails(uncachedIds);
            
            // 缓存新查询的用户
            Map newCacheMap = uncachedUsers.stream()
                .collect(Collectors.toMap(
                    user -> USER_CACHE_PREFIX + user.getId(),
                    user -> user
                ));
            
            redisTemplate.opsForValue().multiSet(newCacheMap);
            newCacheMap.keySet().forEach(key -> redisTemplate.expire(key, CACHE_TTL));
            
            cachedUsers.putAll(newCacheMap);
        }
        
        // 映射为 DTO
        return batchIds.stream()
            .map(id -> cachedUsers.get(USER_CACHE_PREFIX + id))
            .filter(Objects::nonNull)
            .map(user -> userMapper.mapUserWithPermissions(user, context))
            .collect(Collectors.toList());
    }
    
    private Map getCachedUsers(List ids) {
        List cacheKeys = ids.stream()
            .map(id -> USER_CACHE_PREFIX + id)
            .collect(Collectors.toList());
        
        List cachedValues = redisTemplate.opsForValue().multiGet(cacheKeys);
        
        Map result = new HashMap<>();
        for (int i = 0; i < cacheKeys.size(); i++) {
            Object value = cachedValues.get(i);
            if (value instanceof User) {
                result.put(cacheKeys.get(i), (User) value);
            }
        }
        
        return result;
    }
    
    private String buildPageCacheKey(UserQueryCriteria criteria, Pageable pageable, SecurityContext context) {
        return USER_LIST_CACHE_PREFIX + 
            criteria.hashCode() + ":" + 
            pageable.hashCode() + ":" + 
            context.getUserId();
    }
    
    @SuppressWarnings("unchecked")
    private Page getCachedPage(String cacheKey) {
        return (Page) redisTemplate.opsForValue().get(cacheKey);
    }
    
    private void cachePage(String cacheKey, Page page) {
        redisTemplate.opsForValue().set(cacheKey, page, Duration.ofMinutes(10));
    }
    
    private void evictLocalCache(Long userId) {
        // 清除本地缓存的实现
        // 这里可以使用 Caffeine 或其他本地缓存实现
    }
}

/**
 * 用户更新事件
 */
public class UserUpdatedEvent {
    private final Long userId;
    private final String updateType;
    private final LocalDateTime timestamp;
    
    public UserUpdatedEvent(Long userId, String updateType) {
        this.userId = userId;
        this.updateType = updateType;
        this.timestamp = LocalDateTime.now();
    }
    
    // getter 方法...
    public Long getUserId() { return userId; }
    public String getUpdateType() { return updateType; }
    public LocalDateTime getTimestamp() { return timestamp; }
}

/**
 * 用户查询条件
 */
public class UserQueryCriteria {
    private String username;
    private String email;
    private Integer status;
    private Long departmentId;
    private List roleNames;
    private LocalDateTime createTimeStart;
    private LocalDateTime createTimeEnd;
    
    // 构造函数和 getter/setter 方法...
    public UserQueryCriteria() {}
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public Integer getStatus() { return status; }
    public void setStatus(Integer status) { this.status = status; }
    
    public Long getDepartmentId() { return departmentId; }
    public void setDepartmentId(Long departmentId) { this.departmentId = departmentId; }
    
    public List getRoleNames() { return roleNames; }
    public void setRoleNames(List roleNames) { this.roleNames = roleNames; }
    
    public LocalDateTime getCreateTimeStart() { return createTimeStart; }
    public void setCreateTimeStart(LocalDateTime createTimeStart) { this.createTimeStart = createTimeStart; }
    
    public LocalDateTime getCreateTimeEnd() { return createTimeEnd; }
    public void setCreateTimeEnd(LocalDateTime createTimeEnd) { this.createTimeEnd = createTimeEnd; }
    
    @Override
    public int hashCode() {
        return Objects.hash(username, email, status, departmentId, roleNames, createTimeStart, createTimeEnd);
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        
        UserQueryCriteria that = (UserQueryCriteria) obj;
        return Objects.equals(username, that.username) &&
               Objects.equals(email, that.email) &&
               Objects.equals(status, that.status) &&
               Objects.equals(departmentId, that.departmentId) &&
               Objects.equals(roleNames, that.roleNames) &&
               Objects.equals(createTimeStart, that.createTimeStart) &&
               Objects.equals(createTimeEnd, that.createTimeEnd);
    }
}


实施效果分析

性能提升对比

映射性能基准测试

/**
 * 用户映射性能基准测试
 */
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
public class UserMappingBenchmark {
    
    private UserMapper userMapper;
    private User testUser;
    private List testUsers;
    
    @Setup
    public void setup() {
        // 初始化映射器和测试数据
        userMapper = Mappers.getMapper(UserMapper.class);
        testUser = createComplexUser();
        testUsers = createUserList(1000);
    }
    
    @Benchmark
    public UserDtoV1 benchmarkV1Mapping() {
        return userMapper.toV1Dto(testUser);
    }
    
    @Benchmark
    public UserDtoV2 benchmarkV2Mapping() {
        return userMapper.toV2Dto(testUser);
    }
    
    @Benchmark
    public UserAdminDto benchmarkAdminMapping() {
        return userMapper.toAdminDto(testUser);
    }
    
    @Benchmark
    public List benchmarkBatchMapping() {
        return userMapper.toV2Dtos(testUsers);
    }
    
    @Benchmark
    public List benchmarkOptimizedBatchMapping() {
        return testUsers.parallelStream()
            .map(userMapper::toV2DtoOptimized)
            .collect(Collectors.toList());
    }
    
    // 辅助方法...
    private User createComplexUser() {
        // 创建包含完整嵌套关系的复杂用户对象
        User user = new User("testuser", "test@example.com", "13800138000");
        user.setId(1L);
        
        // 用户资料
        UserProfile profile = new UserProfile(user, "测试用户");
        profile.setGender("M");
        profile.setBirthday(LocalDate.of(1990, 1, 1));
        profile.setAddress("北京市朝阳区");
        user.setProfile(profile);
        
        // 部门信息
        Department department = new Department("技术部", "TECH", null);
        department.setId(1L);
        user.setDepartment(department);
        
        // 角色信息
        Role role1 = new Role("DEVELOPER", "开发者");
        role1.setId(1L);
        Role role2 = new Role("TEAM_LEAD", "团队负责人");
        role2.setId(2L);
        user.setRoles(Set.of(role1, role2));
        
        return user;
    }
    
    private List createUserList(int count) {
        return IntStream.range(0, count)
            .mapToObj(i -> createComplexUser())
            .collect(Collectors.toList());
    }
}

性能测试结果

测试场景手动映射BeanUtilsAtlas Mapper性能提升
V1 简单映射1,200μs850μs45μs96%
V2 复杂映射3,500μs2,800μs120μs96%
管理员映射5,200μs4,100μs180μs96%
批量映射(1000个)2.1s1.8s85ms95%
并行批量映射1.2s1.1s25ms98%

内存使用对比

场景手动映射BeanUtilsAtlas Mapper内存节省
单次映射2.5KB1.8KB0.3KB88%
批量映射(1000个)85MB72MB15MB82%
并发映射156MB134MB28MB82%

开发效率提升

代码量对比

//  手动映射代码(复杂且易错)
public UserDtoV2 manualMapping(User user) {
    if (user == null) return null;
    
    UserDtoV2 dto = new UserDtoV2();
    dto.setId(user.getId());
    dto.setUsername(user.getUsername());
    dto.setEmail(user.getEmail());
    dto.setPhone(user.getPhone());
    
    // 状态转换
    if (user.getStatus() != null) {
        switch (user.getStatus()) {
            case 0: dto.setStatus("禁用"); break;
            case 1: dto.setStatus("正常"); break;
            case 2: dto.setStatus("锁定"); break;
            case 3: dto.setStatus("待激活"); break;
            default: dto.setStatus("未知"); break;
        }
    }
    
    // 日期格式化
    if (user.getCreateTime() != null) {
        dto.setCreateTime(user.getCreateTime().format(
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }
    
    if (user.getLastLoginTime() != null) {
        dto.setLastLoginTime(user.getLastLoginTime().format(
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }
    
    dto.setLoginCount(user.getLoginCount());
    
    // 用户资料映射
    if (user.getProfile() != null) {
        UserProfile profile = user.getProfile();
        UserProfileDto profileDto = new UserProfileDto();
        profileDto.setRealName(profile.getRealName());
        profileDto.setAvatarUrl(profile.getAvatarUrl());
        
        if (profile.getGender() != null) {
            switch (profile.getGender()) {
                case "M": profileDto.setGender("男"); break;
                case "F": profileDto.setGender("女"); break;
                default: profileDto.setGender("未知"); break;
            }
        }
        
        if (profile.getBirthday() != null) {
            profileDto.setBirthday(profile.getBirthday().format(
                DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            profileDto.setAge(Period.between(profile.getBirthday(), 
                LocalDate.now()).getYears());
        }
        
        profileDto.setAddress(profile.getAddress());
        profileDto.setBio(profile.getBio());
        profileDto.setWebsite(profile.getWebsite());
        
        dto.setProfile(profileDto);
    }
    
    // 部门信息映射
    if (user.getDepartment() != null) {
        dto.setDepartmentName(user.getDepartment().getName());
        dto.setDepartmentPath(user.getDepartment().getFullPath());
    }
    
    // 角色信息映射
    if (user.getRoles() != null && !user.getRoles().isEmpty()) {
        List roleNames = user.getRoles().stream()
            .map(Role::getDisplayName)
            .filter(Objects::nonNull)
            .sorted()
            .collect(Collectors.toList());
        dto.setRoleNames(roleNames);
    }
    
    dto.setTags(user.getTags());
    
    return dto;
}

//  Atlas Mapper 映射(简洁高效)
UserDtoV2 dto = userMapper.toV2Dto(user);

开发效率统计

指标手动映射Atlas Mapper效率提升
映射代码行数387行15行96%
开发时间4小时30分钟87%
测试代码行数156行45行71%
Bug 修复时间2小时15分钟87%
维护时间1小时/月10分钟/月83%

系统架构收益

微服务集成效果

/**
 * 微服务间数据传输标准化
 */
@FeignClient(name = "user-service")
public interface UserServiceClient {
    
    @GetMapping("/api/v2/users/{id}")
    ApiResponse getUserById(@PathVariable Long id);
    
    @PostMapping("/api/v2/users/batch")
    ApiResponse> getUsersByIds(@RequestBody List ids);
}

// 其他服务中的使用
@Service
public class OrderService {
    
    private final UserServiceClient userServiceClient;
    
    public OrderDetailDto getOrderWithUser(Long orderId) {
        Order order = orderRepository.findById(orderId);
        
        // 调用用户服务获取用户信息
        UserDtoV2 user = userServiceClient.getUserById(order.getUserId()).getData();
        
        // 组装订单详情
        OrderDetailDto dto = orderMapper.toDetailDto(order);
        dto.setUserInfo(user);
        
        return dto;
    }
}

架构优化收益

方面优化前优化后改进效果
服务间调用不统一格式标准化 DTO集成效率提升 60%
数据一致性手动保证自动映射错误率降低 85%
版本兼容性困难多版本支持升级成本降低 70%
性能监控缺失完整监控问题定位效率提升 80%

学习成果总结

张工的技能提升路径

1. 架构设计能力

  • 微服务设计:掌握了服务间数据传输的标准化设计
  • 缓存架构:学会了多级缓存的设计和实现
  • 性能优化:理解了批量处理和异步映射的优化策略
  • 权限控制:掌握了基于上下文的权限敏感数据处理

2. 技术深度提升

  • 高级映射技巧:条件映射、自定义转换器、批量优化
  • Spring 生态集成:缓存、异步处理、事件驱动
  • 监控和调试:性能监控、链路追踪、问题诊断
  • 测试策略:单元测试、性能测试、集成测试

3. 工程实践经验

  • 代码质量:编写可维护、高性能的映射代码
  • 团队协作:制定映射规范,推动技术落地
  • 问题解决:处理复杂的业务场景和性能瓶颈

项目收益总结

技术收益

  • 性能提升:映射性能提升 95%,内存使用减少 82%
  • 开发效率:代码量减少 96%,开发时间节省 87%
  • 系统稳定性:错误率降低 85%,可用性提升到 99.9%

业务收益

  • 用户体验:API 响应时间减少 60%
  • 运维成本:服务器资源使用减少 40%
  • 开发成本:新功能开发时间缩短 50%

团队收益

  • 技术规范:建立了统一的映射开发规范
  • 知识传承:完整的技术文档和最佳实践
  • 能力提升:团队整体技术水平显著提升

案例总结:通过 Atlas Mapper 在微服务架构中的深度应用,张工不仅解决了复杂的数据映射问题,还建立了高性能、可扩展的用户中心服务。这个案例展示了框架在企业级应用中的强大能力,为中级开发者提供了完整的架构设计和性能优化指南。