从0到1精通Mongo-Plus:核心模块深度解析与实战指南

从0到1精通Mongo-Plus:核心模块深度解析与实战指南

【免费下载链接】mongo-plus 🔥🔥🔥使用MyBatisPlus的方式,优雅的操作MongoDB 【免费下载链接】mongo-plus 项目地址: https://gitcode.com/aizuda/mongo-plus

引言:MongoDB开发的痛点与解决方案

你是否还在为MongoDB复杂的查询语法而头疼?是否在寻找一种像MyBatis-Plus操作关系型数据库那样优雅的方式来操作MongoDB?Mongo-Plus(MongoDB增强工具包)正是为解决这些问题而生。本文将带你深入探索Mongo-Plus的核心模块,掌握其设计理念与使用方法,让你的MongoDB开发效率提升10倍!

读完本文,你将获得:

  • 全面了解Mongo-Plus的架构设计与核心模块
  • 掌握条件构造器的高级用法与查询优化技巧
  • 学会使用聚合操作实现复杂数据分析
  • 理解并应用Mongo-Plus的事务与数据安全机制
  • 精通自定义扩展与性能调优的实用方法

1. Mongo-Plus整体架构概览

Mongo-Plus采用分层设计,核心模块之间既相互独立又协同工作,为开发者提供了一站式的MongoDB操作解决方案。

1.1 架构设计图

mermaid

1.2 核心模块功能矩阵

模块名称主要功能核心类典型应用场景
条件构造模块构建查询条件、更新条件QueryWrapper, UpdateWrapper数据查询、更新操作
聚合操作模块实现MongoDB聚合管道AggregateWrapper, Accumulators统计分析、数据报表
映射转换模块Java对象与BSON文档转换MongoConverter, TypeHandlerORM映射、类型处理
事务管理模块支持事务操作TransactionHandler, MongoTransactional数据一致性保障
数据安全模块数据加密、脱敏Encryptor, DesensitizationHandler敏感信息保护
扩展机制模块提供拦截、自定义处理Interceptor, MetaObjectHandler业务逻辑增强
基础支持模块工具类、异常处理等基础设施MongoUtil, MongoPlusException通用功能支持

2. 条件构造模块深度解析

条件构造模块是Mongo-Plus的核心,提供了强大而灵活的查询条件构建能力,支持链式编程,极大简化了MongoDB查询的编写。

2.1 核心类层次结构

mermaid

2.2 条件构造器使用详解

2.2.1 基本查询条件构建

Mongo-Plus提供了两种风格的条件构造器:传统字符串列名方式和Lambda表达式方式。Lambda方式可以提供更好的类型安全和代码提示。

传统方式示例:

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "张三")
            .ne("status", 0)
            .gt("age", 18)
            .like("email", "@qq.com")
            .between("create_time", "2023-01-01", "2023-12-31")
            .orderByDesc("create_time")
            .select("id", "name", "age", "email");

List<User> userList = userMapper.selectList(queryWrapper);

Lambda方式示例:

LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
lambdaQuery.eq(User::getName, "张三")
           .ne(User::getStatus, 0)
           .gt(User::getAge, 18)
           .like(User::getEmail, "@qq.com")
           .between(User::getCreateTime, "2023-01-01", "2023-12-31")
           .orderByDesc(User::getCreateTime)
           .select(User::getId, User::getName, User::getAge, User::getEmail);

List<User> userList = userMapper.selectList(lambdaQuery);
2.2.2 高级查询功能

组合条件与嵌套查询:

LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getStatus, 1)
           .and(wq -> wq.gt(User::getAge, 18).or().like(User::getEmail, "@admin.com"))
           .or(wq -> wq.eq(User::getVipLevel, 3).ge(User::getCreateTime, "2023-01-01"))
           .nested(wq -> wq.isNotNull(User::getPhone).ne(User::getPhone, ""));

子查询示例:

LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.inSql(User::getId, "SELECT user_id FROM user_role WHERE role_id = 1");

Exists查询:

LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.exists("SELECT 1 FROM orders WHERE orders.user_id = user.id AND orders.status = 1");
2.2.3 更新条件构建

基本更新:

UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", 1)
             .set("name", "张三更新")
             .set("age", 25)
             .inc("login_count", 1);

int rows = userMapper.update(null, updateWrapper);

Lambda更新:

LambdaUpdateWrapper<User> lambdaUpdate = new LambdaUpdateWrapper<>();
lambdaUpdate.eq(User::getId, 1)
            .set(User::getName, "张三更新")
            .set(User::getAge, 25)
            .inc(User::getLoginCount, 1);

int rows = userMapper.update(null, lambdaUpdate);

条件更新:

LambdaUpdateWrapper<User> lambdaUpdate = new LambdaUpdateWrapper<>();
lambdaUpdate.eq(User::getStatus, 1)
            .setSql("age = age + 1")
            .set(User::getUpdateTime, new Date());

int rows = userMapper.update(null, lambdaUpdate);

2.3 查询优化技巧

2.3.1 投影查询(只返回需要的字段)
LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
lambdaQuery.eq(User::getId, 1)
           .select(User::getId, User::getName, User::getEmail);
2.3.2 分页查询
PageParam pageParam = new PageParam();
pageParam.setPageNum(1);  // 页码,从1开始
pageParam.setPageSize(10); // 每页条数

LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
lambdaQuery.eq(User::getStatus, 1)
           .orderByDesc(User::getCreateTime);

PageResult<User> pageResult = userMapper.selectPage(pageParam, lambdaQuery);

// 分页结果信息
long total = pageResult.getTotalSize();      // 总记录数
long pages = pageResult.getTotalPages();     // 总页数
List<User> records = pageResult.getContentData(); // 当前页数据
2.3.3 性能监控与分析

Mongo-Plus提供了查询性能监控功能,可以通过拦截器记录慢查询:

@Configuration
public class MongoPlusConfig {
    @Bean
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor interceptor = new PerformanceInterceptor();
        interceptor.setMaxTime(100); // 设置慢查询阈值,单位毫秒
        interceptor.setFormat(true); // 是否格式化SQL
        return interceptor;
    }
}

3. 聚合操作模块详解

Mongo-Plus的聚合操作模块提供了强大而直观的API,简化了MongoDB聚合管道的构建过程,支持复杂的数据统计分析需求。

3.1 聚合操作核心组件

Mongo-Plus的聚合模块主要包含以下核心类:

  • AggregateWrapper: 聚合操作的入口类,用于构建完整的聚合管道
  • LambdaAggregateWrapper: Lambda风格的聚合构造器,提供类型安全的聚合操作
  • Accumulators: 聚合累加器工具类,提供各种聚合操作函数
  • AggregateOperator: 聚合操作符工具类,提供各种管道操作符

3.2 常用聚合操作示例

3.2.1 基本聚合示例:用户订单统计
// 统计每个用户的订单数量和总金额
LambdaAggregateWrapper<User> aggregateWrapper = new LambdaAggregateWrapper<>();
aggregateWrapper.lookup(Order.class, User::getId, Order::getUserId, "orders")
                .unwind("orders")
                .groupBy(User::getId)
                .groupBy(User::getName)
                .count("orderCount")
                .sum("orders.totalAmount", "totalAmount")
                .project("id", "name", "orderCount", "totalAmount");

List<Map<String, Object>> result = userMapper.aggregateList(aggregateWrapper);
3.2.2 复杂聚合示例:商品销售分析
LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
aggregateWrapper.match(new QueryWrapper<Order>()
                        .between("create_time", "2023-01-01", "2023-12-31"))
                .groupBy("product_id")
                .sum("quantity", "totalQuantity")
                .sum("totalAmount", "totalSales")
                .avg("unitPrice", "avgPrice")
                .max("create_time", "lastSaleTime")
                .lookup(Product.class, "product_id", "_id", "product")
                .unwind("product")
                .project(Projections.fields(
                    Projections.excludeId(),
                    Projections.include("product_id", "totalQuantity", "totalSales", "avgPrice", "lastSaleTime"),
                    Projections.computed("product.name", "productName")
                ))
                .sort(Sorts.desc("totalSales"))
                .limit(10);

List<Map<String, Object>> topProducts = orderMapper.aggregateList(aggregateWrapper);

3.3 高级聚合操作

3.3.1 多阶段聚合管道
LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
// 阶段1: 匹配条件
aggregateWrapper.match(new QueryWrapper<Order>().eq("status", 1))
// 阶段2: 分组统计
                .groupBy("user_id")
                .sum("totalAmount", "totalSpent")
                .count("orderCount")
// 阶段3: 关联用户信息
                .lookup(User.class, "user_id", "_id", "userInfo")
                .unwind("userInfo")
// 阶段4: 投影需要的字段
                .project(Projections.fields(
                    Projections.excludeId(),
                    Projections.include("user_id", "totalSpent", "orderCount"),
                    Projections.computed("userInfo.name", "userName"),
                    Projections.computed("userInfo.email", "userEmail")
                ))
// 阶段5: 筛选高价值用户
                .match(new QueryWrapper<Map>().gt("totalSpent", 1000))
// 阶段6: 排序
                .sort(Sorts.desc("totalSpent"))
// 阶段7: 限制结果数量
                .limit(20);
3.3.2 使用累加器进行复杂计算

Mongo-Plus的Accumulators类提供了丰富的聚合累加器函数:

LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
aggregateWrapper.groupBy("product_id")
                .sum("quantity", "totalQuantity")
                .sum("totalAmount", "totalSales")
                .avg("unitPrice", "avgPrice")
                .max("unitPrice", "maxPrice")
                .min("unitPrice", "minPrice")
                .push("orderDate", "orderDates")
                .addToSet("userId", "customerIds")
                .first("productName", "productName");
3.3.3 条件聚合与分支处理

使用AggregationOperators.cond实现条件聚合:

LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
aggregateWrapper.groupBy("user_id")
                .sum("totalAmount", "totalSpent")
                .count("orderCount")
                .addFields("customerLevel", 
                    AggregationOperators.cond(
                        ConditionalOperators.gt("totalSpent", 10000), 
                        "VIP", 
                        ConditionalOperators.cond(
                            ConditionalOperators.gt("totalSpent", 5000), 
                            "Gold", 
                            "Silver"
                        )
                    )
                );

3.4 聚合结果处理

Mongo-Plus提供了多种聚合结果处理方式:

3.4.1 聚合结果映射到实体类
@Data
public class UserOrderSummary {
    private String userId;
    private String userName;
    private Integer orderCount;
    private BigDecimal totalAmount;
}

LambdaAggregateWrapper<User> aggregateWrapper = new LambdaAggregateWrapper<>();
// ... 构建聚合管道

List<UserOrderSummary> result = userMapper.aggregateList(aggregateWrapper, UserOrderSummary.class);
3.4.2 聚合分页查询
PageParam pageParam = new PageParam();
pageParam.setPageNum(1);
pageParam.setPageSize(10);

LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
// ... 构建聚合管道

PageResult<Map<String, Object>> pageResult = orderMapper.aggregatePage(pageParam, aggregateWrapper);

4. 映射转换模块

映射转换模块是Mongo-Plus实现ORM(对象关系映射)功能的核心,负责Java对象与MongoDB BSON文档之间的双向转换。

4.1 核心转换机制

Mongo-Plus的映射转换基于以下核心组件:

  • MongoConverter: 顶层转换接口,定义了Java对象与BSON文档之间的转换方法
  • MappingMongoConverter: 默认转换器实现,提供基本的类型转换功能
  • TypeHandler: 类型处理器接口,用于自定义特定类型的转换逻辑
  • FieldHandler: 字段处理器接口,用于自定义字段级别的处理逻辑

4.2 自定义类型转换器

当Mongo-Plus内置的类型转换器无法满足需求时,我们可以自定义类型转换器:

4.2.1 自定义日期类型转换器
@Component
public class CustomDateTypeHandler implements TypeHandler<LocalDateTime> {
    
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    @Override
    public Object getParameter(LocalDateTime parameter) {
        // Java对象转BSON值
        return parameter == null ? null : Date.from(parameter.atZone(ZoneId.systemDefault()).toInstant());
    }
    
    @Override
    public LocalDateTime getResult(Object result) {
        // BSON值转Java对象
        if (result == null) {
            return null;
        }
        if (result instanceof Date) {
            return ((Date) result).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        }
        if (result instanceof String) {
            return LocalDateTime.parse((String) result, FORMATTER);
        }
        throw new TypeConvertException("Unsupported type conversion from " + result.getClass() + " to LocalDateTime");
    }
}
4.2.2 注册自定义类型转换器
@Configuration
public class MongoPlusConfig {
    
    @Bean
    public MongoConverter mongoConverter() {
        MappingMongoConverter converter = new MappingMongoConverter();
        // 注册自定义类型转换器
        converter.getTypeHandlerRegistry().register(LocalDateTime.class, new CustomDateTypeHandler());
        return converter;
    }
}

4.3 字段级自定义处理

Mongo-Plus提供了字段级别的自定义处理机制,可以通过注解或自定义FieldHandler实现:

4.3.1 使用注解进行字段处理
@Data
@Document("user")
public class User {
    @Id
    private String id;
    
    private String name;
    
    @Field("user_age")
    private Integer age;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
    
    @EncryptField(type = EncryptType.AES)
    private String idCard;
    
    @SensitiveField(type = SensitiveType.PHONE)
    private String phone;
}
4.3.2 自定义字段处理器
@Component
public class CustomFieldHandler implements FieldHandler {
    
    @Override
    public Object process(Object value, Field field, Document document) {
        if (field.getName().equals("password") && value != null) {
            // 对密码进行加密处理
            return PasswordUtils.encode((String) value);
        }
        return value;
    }
}

4.4 高级映射功能

4.4.1 嵌套对象映射

Mongo-Plus支持复杂对象的嵌套映射:

@Data
@Document("order")
public class Order {
    @Id
    private String id;
    
    private String orderNo;
    
    private User buyer;  // 嵌套User对象
    
    private List<OrderItem> items;  // 嵌套集合
    
    private BigDecimal totalAmount;
    
    private Date createTime;
}

@Data
public class OrderItem {
    private String productId;
    
    private String productName;
    
    private Integer quantity;
    
    private BigDecimal unitPrice;
}
4.4.2 枚举类型映射

Mongo-Plus提供了灵活的枚举类型映射机制:

// 枚举定义
public enum OrderStatus {
    PENDING(0, "待支付"),
    PAID(1, "已支付"),
    SHIPPED(2, "已发货"),
    DELIVERED(3, "已送达"),
    CANCELLED(4, "已取消");
    
    private final int code;
    private final String desc;
    
    // 构造函数、getter等省略
}

// 实体类中使用
@Data
@Document("order")
public class Order {
    @Id
    private String id;
    
    private String orderNo;
    
    @EnumValue // 存储枚举的code值
    private OrderStatus status;
    
    // 其他字段省略
}

5. 事务与数据安全模块

Mongo-Plus提供了完善的事务支持和数据安全保障机制,确保数据操作的一致性和安全性。

5.1 事务管理

Mongo-Plus支持两种事务模式:本地事务和分布式事务。

5.1.1 本地事务使用
@Service
public class OrderService {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private OrderItemMapper orderItemMapper;
    
    @Transactional
    public void createOrder(Order order, List<OrderItem> items) {
        // 保存订单
        orderMapper.insert(order);
        
        // 保存订单项
        for (OrderItem item : items) {
            item.setOrderId(order.getId());
            orderItemMapper.insert(item);
        }
        
        // 更新商品库存
        // ...
    }
}
5.1.2 事务配置
@Configuration
public class TransactionConfig {
    
    @Bean
    public TransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
        MongoTransactionManager transactionManager = new MongoTransactionManager();
        transactionManager.setDbFactory(dbFactory);
        transactionManager.setDefaultTimeout(60); // 设置默认超时时间,单位秒
        return transactionManager;
    }
}
5.1.3 分布式事务支持

Mongo-Plus通过集成Seata等分布式事务框架,支持跨多个MongoDB实例或混合数据库的分布式事务:

@Configuration
public class SeataConfig {
    
    @Bean
    public GlobalTransactionScanner globalTransactionScanner() {
        return new GlobalTransactionScanner("mongo-plus-example", "my_test_tx_group");
    }
}

@Service
public class OrderService {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private ProductMapper productMapper;
    
    @GlobalTransactional // 分布式事务注解
    public void createOrder(Order order, List<OrderItem> items) {
        // 保存订单(MongoDB)
        orderMapper.insert(order);
        
        // 更新商品库存(MySQL)
        for (OrderItem item : items) {
            productMapper.decreaseStock(item.getProductId(), item.getQuantity());
        }
    }
}

5.2 数据安全机制

Mongo-Plus提供了多层次的数据安全保障机制,包括数据加密、脱敏、访问控制等。

5.2.1 数据加密

Mongo-Plus支持多种加密算法,可以对敏感数据进行加密存储:

@Configuration
public class EncryptConfig {
    
    @Bean
    public Encryptor aesEncryptor() {
        AESEncryptor encryptor = new AESEncryptor();
        encryptor.setKey("1234567890abcdef"); // 加密密钥
        encryptor.setIv("abcdef1234567890");  // 初始化向量
        return encryptor;
    }
}

// 实体类中使用
@Data
@Document("user")
public class User {
    @Id
    private String id;
    
    private String name;
    
    @EncryptField(type = EncryptType.AES)
    private String idCard;
    
    @EncryptField(type = EncryptType.MD5)
    private String password;
}
5.2.2 数据脱敏

Mongo-Plus支持多种数据脱敏策略,可以在查询时自动对敏感数据进行脱敏处理:

@Data
@Document("user")
public class User {
    @Id
    private String id;
    
    private String name;
    
    @SensitiveField(type = SensitiveType.PHONE)
    private String phone;
    
    @SensitiveField(type = SensitiveType.ID_CARD)
    private String idCard;
    
    @SensitiveField(type = SensitiveType.EMAIL)
    private String email;
}

// 自定义脱敏策略
@Component
public class CustomSensitiveStrategy implements SensitiveStrategy {
    
    @Override
    public String desensitize(String value, SensitiveType type) {
        if (type == SensitiveType.CUSTOM) {
            if (value != null && value.length() > 4) {
                return value.substring(0, 2) + "****" + value.substring(value.length() - 2);
            }
        }
        return value;
    }
}
5.2.3 乐观锁

Mongo-Plus提供了乐观锁支持,通过版本号机制实现并发控制:

@Data
@Document("product")
public class Product {
    @Id
    private String id;
    
    private String name;
    
    private Integer stock;
    
    @Version
    private Integer version; // 版本号字段
}

@Service
public class ProductService {
    
    @Autowired
    private ProductMapper productMapper;
    
    public boolean decreaseStock(String productId, int quantity) {
        Product product = productMapper.selectById(productId);
        if (product.getStock() < quantity) {
            return false;
        }
        
        UpdateWrapper<Product> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", productId)
                     .eq("version", product.getVersion()) // 乐观锁条件
                     .set("stock", product.getStock() - quantity)
                     .set("version", product.getVersion() + 1);
        
        int rows = productMapper.update(null, updateWrapper);
        return rows > 0;
    }
}

6. 扩展机制与插件开发

Mongo-Plus提供了灵活的扩展机制,允许开发者通过拦截器、自定义处理器等方式扩展框架功能。

6.1 拦截器体系

Mongo-Plus的拦截器体系允许开发者在数据访问的各个阶段进行拦截和增强:

6.1.1 自定义查询拦截器
@Component
public class QueryInterceptor implements Interceptor {
    
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 拦截查询操作
        if (invocation.getMethod().getName().startsWith("select")) {
            long startTime = System.currentTimeMillis();
            
            // 执行原方法
            Object result = invocation.proceed();
            
            long endTime = System.currentTimeMillis();
            long costTime = endTime - startTime;
            
            // 记录慢查询
            if (costTime > 100) {
                log.warn("Slow query detected: {} ms, Method: {}", 
                         costTime, invocation.getMethod().getName());
            }
            
            return result;
        }
        
        return invocation.proceed();
    }
    
    @Override
    public Object plugin(Object target) {
        // 只对Mapper接口应用拦截器
        if (target instanceof Mapper) {
            return Plugin.wrap(target, this);
        }
        return target;
    }
}
6.1.2 分页拦截器

Mongo-Plus内置了分页拦截器,也可以自定义分页逻辑:

@Component
public class CustomPageInterceptor implements Interceptor {
    
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        Object[] args = invocation.getArgs();
        
        // 判断是否为分页查询方法
        if (method.getName().equals("selectPage") && args.length >= 2 
            && args[0] instanceof PageParam && args[1] instanceof QueryWrapper) {
            
            PageParam pageParam = (PageParam) args[0];
            QueryWrapper<?> queryWrapper = (QueryWrapper<?>) args[1];
            
            // 添加分页信息到查询条件
            long offset = (pageParam.getPageNum() - 1) * pageParam.getPageSize();
            queryWrapper.last("LIMIT " + offset + ", " + pageParam.getPageSize());
            
            // 先查询总数
            long total = countTotal(queryWrapper);
            
            // 执行查询
            List<?> result = (List<?>) invocation.proceed();
            
            // 构建分页结果
            PageResult<?> pageResult = new PageResult<>();
            pageResult.setContentData(result);
            pageResult.setPageNum(pageParam.getPageNum());
            pageResult.setPageSize(pageParam.getPageSize());
            pageResult.setTotalSize(total);
            pageResult.setTotalPages((total + pageParam.getPageSize() - 1) / pageParam.getPageSize());
            
            return pageResult;
        }
        
        return invocation.proceed();
    }
    
    private long countTotal(QueryWrapper<?> queryWrapper) {
        // 实现总数查询逻辑
        // ...
    }
}

6.2 自定义处理器

Mongo-Plus提供了多种处理器接口,可以通过实现这些接口来自定义特定功能:

6.2.1 自定义元对象处理器

元对象处理器用于实现自动填充等功能:

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    
    @Override
    public void insertFill(MetaObject metaObject) {
        // 插入时自动填充创建时间
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
        this.strictInsertFill(metaObject, "status", Integer.class, 1);
        
        // 自动填充创建人
        User currentUser = SecurityUtils.getCurrentUser();
        if (currentUser != null) {
            this.strictInsertFill(metaObject, "createBy", String.class, currentUser.getId());
        }
    }
    
    @Override
    public void updateFill(MetaObject metaObject) {
        // 更新时自动填充更新时间
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
        
        // 自动填充更新人
        User currentUser = SecurityUtils.getCurrentUser();
        if (currentUser != null) {
            this.strictUpdateFill(metaObject, "updateBy", String.class, currentUser.getId());
        }
    }
}
6.2.2 自定义ID生成器

Mongo-Plus支持自定义ID生成策略:

@Component
public class SnowflakeIdGenerator implements IdentifierGenerator {
    
    private final Snowflake snowflake = new Snowflake(1, 1);
    
    @Override
    public Object nextId(Object entity) {
        // 使用雪花算法生成ID
        return snowflake.nextIdStr();
    }
}

@Configuration
public class MongoPlusConfig {
    
    @Bean
    public IdentifierGenerator idGenerator() {
        return new SnowflakeIdGenerator();
    }
}

6.3 插件开发最佳实践

6.3.1 插件开发规范
  1. 单一职责原则:一个插件只负责一项功能
  2. 配置化:插件应支持通过配置开启/关闭或调整行为
  3. 兼容性:考虑与其他插件的兼容性
  4. 性能影响:最小化插件对性能的影响
  5. 可测试性:设计时考虑可测试性
6.3.2 插件注册与排序
@Configuration
public class InterceptorConfig {
    
    @Bean
    public Interceptor[] interceptors() {
        // 拦截器排序,按数组顺序执行
        return new Interceptor[] {
            new LogInterceptor(),      // 日志拦截器
            new PerformanceInterceptor(), // 性能监控拦截器
            new DataScopeInterceptor()  // 数据权限拦截器
        };
    }
}

7. 实战案例分析

7.1 电商订单系统设计

7.1.1 数据模型设计
// 用户模型
@Data
@Document("user")
public class User {
    @Id
    private String id;
    
    private String username;
    
    private String phone;
    
    private String email;
    
    private Integer status;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;
}

// 商品模型
@Data
@Document("product")
public class Product {
    @Id
    private String id;
    
    private String name;
    
    private String categoryId;
    
    private BigDecimal price;
    
    private Integer stock;
    
    private String imageUrl;
    
    private Integer status;
    
    @Version
    private Integer version; // 乐观锁版本号
}

// 订单模型
@Data
@Document("order")
public class Order {
    @Id
    private String id;
    
    private String orderNo;
    
    private String userId;
    
    private List<OrderItem> items;
    
    private BigDecimal totalAmount;
    
    private Integer status;
    
    private String paymentMethod;
    
    private Date payTime;
    
    private Date deliveryTime;
    
    private Date receiveTime;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;
}

// 订单项模型
@Data
public class OrderItem {
    private String productId;
    
    private String productName;
    
    private BigDecimal price;
    
    private Integer quantity;
    
    private BigDecimal totalPrice;
}
7.1.2 订单创建流程实现
@Service
public class OrderService {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private ProductMapper productMapper;
    
    @Autowired
    private InventoryService inventoryService;
    
    @Transactional
    public String createOrder(OrderCreateDTO orderDTO) {
        // 1. 生成订单号
        String orderNo = OrderNoGenerator.generate();
        
        // 2. 扣减库存(使用乐观锁)
        boolean inventoryResult = inventoryService.decreaseBatch(orderDTO.getItems());
        if (!inventoryResult) {
            throw new BusinessException("库存不足");
        }
        
        // 3. 创建订单
        Order order = new Order();
        order.setOrderNo(orderNo);
        order.setUserId(orderDTO.getUserId());
        order.setStatus(OrderStatus.PENDING.getValue());
        order.setTotalAmount(calculateTotal(orderDTO.getItems()));
        
        // 4. 设置订单项
        List<OrderItem> items = orderDTO.getItems().stream().map(item -> {
            OrderItem orderItem = new OrderItem();
            orderItem.setProductId(item.getProductId());
            orderItem.setProductName(item.getProductName());
            orderItem.setPrice(item.getPrice());
            orderItem.setQuantity(item.getQuantity());
            orderItem.setTotalPrice(item.getPrice().multiply(new BigDecimal(item.getQuantity())));
            return orderItem;
        }).collect(Collectors.toList());
        
        order.setItems(items);
        
        // 5. 保存订单
        orderMapper.insert(order);
        
        // 6. 发送订单创建事件
        eventPublisher.publishEvent(new OrderCreatedEvent(order));
        
        return order.getId();
    }
    
    private BigDecimal calculateTotal(List<OrderItemDTO> items) {
        return items.stream()
            .map(item -> item.getPrice().multiply(new BigDecimal(item.getQuantity())))
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}
7.1.3 订单查询与统计分析
@Service
public class OrderStatisticsService {
    
    @Autowired
    private MongoTemplate mongoTemplate;
    
    /**
     * 统计用户订单情况
     */
    public UserOrderStatsDTO statsUserOrders(String userId) {
        LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
        aggregateWrapper.match(new QueryWrapper<Order>().eq("user_id", userId))
                        .groupBy("status")
                        .count("count")
                        .project("status", "count");
        
        List<Map<String, Object>> result = mongoTemplate.aggregate(aggregateWrapper, Order.class);
        
        UserOrderStatsDTO statsDTO = new UserOrderStatsDTO();
        
        for (Map<String, Object> item : result) {
            Integer status = (Integer) item.get("status");
            Long count = (Long) item.get("count");
            
            switch (OrderStatus.valueOf(status)) {
                case PENDING:
                    statsDTO.setPendingCount(count.intValue());
                    break;
                case PAID:
                    statsDTO.setPaidCount(count.intValue());
                    break;
                case SHIPPED:
                    statsDTO.setShippedCount(count.intValue());
                    break;
                case DELIVERED:
                    statsDTO.setDeliveredCount(count.intValue());
                    break;
                case CANCELLED:
                    statsDTO.setCancelledCount(count.intValue());
                    break;
            }
        }
        
        // 查询总消费金额
        LambdaAggregateWrapper<Order> sumWrapper = new LambdaAggregateWrapper<>();
        sumWrapper.match(new QueryWrapper<Order>().eq("user_id", userId)
                        .in("status", Arrays.asList(OrderStatus.PAID.getValue(), 
                                                   OrderStatus.SHIPPED.getValue(), 
                                                   OrderStatus.DELIVERED.getValue())))
                   .groupBy()
                   .sum("totalAmount", "totalSpent");
        
        List<Map<String, Object>> sumResult = mongoTemplate.aggregate(sumWrapper, Order.class);
        if (!sumResult.isEmpty()) {
            BigDecimal totalSpent = (BigDecimal) sumResult.get(0).get("totalSpent");
            statsDTO.setTotalSpent(totalSpent != null ? totalSpent : BigDecimal.ZERO);
        }
        
        return statsDTO;
    }
    
    /**
     * 商品销售排行
     */
    public List<ProductSalesDTO> productSalesRank(Date startTime, Date endTime, int limit) {
        LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
        aggregateWrapper.match(new QueryWrapper<Order>()
                        .ge("create_time", startTime)
                        .le("create_time", endTime)
                        .eq("status", OrderStatus.DELIVERED.getValue()))
                       .unwind("items")
                       .groupBy("items.product_id")
                       .sum("items.quantity", "salesQuantity")
                       .sum("items.totalPrice", "salesAmount")
                       .project("items.product_id as productId", "salesQuantity", "salesAmount")
                       .sort(Sorts.desc("salesAmount"))
                       .limit(limit);
        
        List<ProductSalesDTO> result = mongoTemplate.aggregate(aggregateWrapper, ProductSalesDTO.class);
        
        // 补充商品名称
        for (ProductSalesDTO dto : result) {
            Product product = productMapper.selectById(dto.getProductId());
            if (product != null) {
                dto.setProductName(product.getName());
            }
        }
        
        return result;
    }
}

7.2 性能优化实践

7.2.1 索引优化
@Data
@Document("order")
@Indexes({
    @Index(fields = "orderNo", unique = true),
    @Index(fields = "userId"),
    @Index(fields = "createTime"),
    @Index(fields = "status,createTime")
})
public class Order {
    // 字段定义省略
}
7.2.2 查询优化
@Service
public class OptimizedQueryService {
    
    @Autowired
    private MongoTemplate mongoTemplate;
    
    /**
     * 优化的订单查询
     */
    public PageResult<Order> optimizedOrderQuery(OrderQueryDTO queryDTO, PageParam pageParam) {
        // 1. 构建查询条件
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        
        // 2. 动态条件
        if (StringUtils.isNotBlank(queryDTO.getUserId())) {
            queryWrapper.eq(Order::getUserId, queryDTO.getUserId());
        }
        
        if (queryDTO.getStatus() != null) {
            queryWrapper.eq(Order::getStatus, queryDTO.getStatus());
        }
        
        if (queryDTO.getStartTime() != null) {
            queryWrapper.ge(Order::getCreateTime, queryDTO.getStartTime());
        }
        
        if (queryDTO.getEndTime() != null) {
            queryWrapper.le(Order::getCreateTime, queryDTO.getEndTime());
        }
        
        // 3. 投影查询,只返回需要的字段
        queryWrapper.select(Order::getId, Order::getOrderNo, Order::getUserId, 
                           Order::getTotalAmount, Order::getStatus, Order::getCreateTime);
        
        // 4. 排序优化
        queryWrapper.orderByDesc(Order::getCreateTime);
        
        // 5. 分页查询
        PageResult<Order> pageResult = orderMapper.selectPage(pageParam, queryWrapper);
        
        return pageResult;
    }
    
    /**
     * 使用聚合管道优化关联查询
     */
    public List<OrderDetailVO> getOrderDetails(String userId) {
        // 使用聚合管道一次性完成关联查询,避免N+1问题
        LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
        aggregateWrapper.match(new QueryWrapper<Order>().eq("user_id", userId))
                        .lookup(User.class, "user_id", "_id", "user")
                        .unwind("user")
                        .project(Projections.fields(
                            Projections.include("id", "orderNo", "totalAmount", "status", "createTime"),
                            Projections.computed("user.name", "userName"),
                            Projections.computed("user.phone", "userPhone")
                        ));
        
        return mongoTemplate.aggregate(aggregateWrapper, OrderDetailVO.class);
    }
}

8. 总结与展望

8.1 核心功能回顾

Mongo-Plus作为一款MongoDB增强工具包,提供了以下核心功能:

  1. 强大的条件构造器:支持链式编程,提供Lambda风格API,简化查询条件构建
  2. 完善的聚合操作支持:提供直观的聚合管道构建API,支持复杂数据分析
  3. 灵活的映射转换机制:支持Java对象与BSON文档的双向转换,支持自定义类型转换
  4. 全面的事务支持:支持本地事务和分布式事务,保障数据一致性
  5. 多层次数据安全:提供数据加密、脱敏、访问控制等安全机制
  6. 丰富的扩展机制:支持拦截器、自定义处理器等多种扩展方式
  7. 高性能:通过优化查询、索引支持等方式提升数据访问性能

8.2 最佳实践总结

  1. 合理设计数据模型:充分利用MongoDB的文档模型特性,合理设计嵌套结构
  2. 优化索引策略:根据查询场景设计合适的索引,提升查询性能
  3. 使用投影查询:只返回需要的字段,减少数据传输和处理开销
  4. 批量操作优先:使用批量操作代替循环单个操作,提升性能
  5. 合理使用聚合管道:利用聚合管道减少客户端与数据库的交互次数
  6. 事务使用原则:只在必要时使用事务,平衡一致性与性能需求
  7. 监控与调优:使用Mongo-Plus提供的性能监控工具,持续优化数据访问性能

8.3 未来发展方向

  1. AI辅助查询优化:结合AI技术,自动分析和优化查询语句
  2. 更完善的分布式事务支持:支持跨多个MongoDB实例的分布式事务
  3. 实时数据分析:集成流处理能力,支持实时数据处理和分析
  4. 多数据源支持:支持MongoDB与其他数据库的混合使用
  5. 更丰富的可视化工具:提供更直观的查询构建和性能分析界面

Mongo-Plus作为一款活跃发展的开源项目,将持续吸收社区反馈,不断完善功能,为开发者提供更优雅、高效的MongoDB操作体验。

9. 附录:常用API速查表

9.1 条件构造器API

方法名说明示例
eq等于eq("name", "张三")
ne不等于ne("status", 0)
gt大于gt("age", 18)
ge大于等于ge("score", 60)
lt小于lt("price", 100)
le小于等于le("stock", 10)
like模糊查询like("name", "%张%")
notLike不匹配模糊查询notLike("name", "%张%")
inIN查询in("id", 1, 2, 3)
notInNOT IN查询notIn("status", 0, 2)
isNull为空isNull("email")
isNotNull不为空isNotNull("phone")
betweenBETWEEN查询between("createTime", "2023-01-01", "2023-12-31")
notBetweenNOT BETWEEN查询notBetween("age", 18, 30)
andAND条件and(i -> i.eq("name", "张三").ne("status", 0))
orOR条件or(i -> i.eq("status", 1).or().eq("status", 2))
nested嵌套条件nested(i -> i.gt("age", 18).lt("age", 30))
apply拼接SQLapply("date_format(create_time, '%Y-%m-%d') = {0}", "2023-01-01")
orderByAsc升序排序orderByAsc("createTime")
orderByDesc降序排序orderByDesc("createTime")
select指定查询字段select("id", "name", "age")

9.2 聚合操作API

方法名说明示例
match过滤文档match(new QueryWrapper<>().eq("status", 1))
groupBy分组groupBy("user_id")
sum求和sum("amount", "totalAmount")
count计数count("orderCount")
avg平均值avg("score", "avgScore")
max最大值max("price", "maxPrice")
min最小值min("price", "minPrice")
lookup关联查询lookup(User.class, "user_id", "_id", "user")
unwind展开数组unwind("items")
project投影project("id", "name", "age")
sort排序sort(Sorts.desc("createTime"))
skip跳过记录skip(10)
limit限制记录数limit(20)
addFields添加字段addFields("fullName", "$concat: ['$firstName', ' ', '$lastName']")
replaceRoot替换根文档replaceRoot("user")

9.3 常用工具类

类名说明主要方法
MongoUtilMongoDB操作工具类getCollection(), executeCommand(), aggregate()
QueryUtil查询工具类buildQuery(), buildSort(), buildPage()
BsonUtilBSON文档处理工具类toDocument(), toJson(), merge()
DateUtil日期处理工具类format(), parse(), addDays()
StringUtil字符串处理工具类isEmpty(), isNotEmpty(), substring()
CollectionUtil集合处理工具类isEmpty(), isNotEmpty(), merge()
ReflectUtil反射工具类getField(), getMethod(), invoke()
SecurityUtil安全工具类encrypt(), decrypt(), md5()

希望本文对你理解和使用Mongo-Plus有所帮助!如果觉得本文有价值,请点赞、收藏、关注三连支持!如有任何问题或建议,欢迎在评论区留言讨论。

下一期预告:《Mongo-Plus高级特性实战:分布式事务与数据一致性保障》

【免费下载链接】mongo-plus 🔥🔥🔥使用MyBatisPlus的方式,优雅的操作MongoDB 【免费下载链接】mongo-plus 项目地址: https://gitcode.com/aizuda/mongo-plus

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值