You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot MongoTemplate查询MongoDB返回全null如何解决

问题根因

故障和BSON转JSON环节无关,是MongoDB文档到Java实体的映射逻辑存在两个核心问题:

  • 字段名无映射匹配:MongoDB存储的字段为下划线命名(emp_cd/leave_type/leave_start/leave_end),但Leave实体定义的是驼峰命名字段(employeeCode/leaveType/startDate/endDate),既没有配置全局驼峰转下划线的命名策略,也没有通过注解指定字段绑定关系,MongoTemplate读取到BSON字段后找不到Java实体中对应的属性,无法完成赋值。
  • 实例化与类型转换缺失:你在配置类中手动实例化MongoTemplate时,跳过了Spring Data MongoDB自带的转换器注册逻辑,既没有适配Java 17 Record类的全参构造实例化规则,也没有注册LocalDate类型和MongoDB ISODate类型的双向转换器,日期字段无法正常解析,Record类也无法通过默认反射机制完成对象填充。

原生读取Document能拿到值,已经排除了数据查询环节的问题,故障完全出在ORM映射阶段。

解决方案

按以下步骤修改即可修复:

  1. 修正Leave实体,添加字段映射注解
    给Record的每个字段添加@Field注解,明确指定和MongoDB字段的绑定关系:

    import org.springframework.data.mongodb.core.mapping.Field;
    import java.time.LocalDate;
    
    public record Leave(
            @Field("emp_cd")
            String employeeCode,
            @Field("leave_type")
            String leaveType,
            @Field("leave_start")
            LocalDate startDate,
            @Field("leave_end")
            LocalDate endDate
    ) {}
    

    如果使用的Spring Boot 2.7小版本低于2.7.12,建议先升级到2.7.12+,避免低版本对Java Record的映射兼容问题;也可以临时把Record改成普通类,添加@Data、无参/全参构造注解验证逻辑。

  2. 修正Mongo配置类,补全转换器与映射上下文
    不要直接手动实例化裸的MongoTemplate,注册必要的日期转换器,确保映射逻辑正常加载:

    import org.springframework.boot.autoconfigure.AutoConfigureOrder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.core.convert.converter.Converter;
    import org.springframework.data.mongodb.MongoDatabaseFactory;
    import org.springframework.data.mongodb.core.MongoTemplate;
    import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
    import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
    import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
    import com.mongodb.client.MongoClient;
    import com.mongodb.client.MongoClients;
    import java.time.LocalDate;
    import java.time.ZoneId;
    import java.util.Arrays;
    import java.util.Date;
    
    @Configuration
    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
    public class ErpConfig {
    
        @Bean
        public MongoClient mongoClient() {
            return MongoClients.create("mongodb://localhost:27017");
        }
    
        @Bean
        public MongoCustomConversions mongoCustomConversions() {
            return new MongoCustomConversions(Arrays.asList(
                    // LocalDate 转 MongoDB ISODate
                    (Converter<LocalDate, Date>) source -> 
                            Date.from(source.atStartOfDay(ZoneId.systemDefault()).toInstant()),
                    // MongoDB ISODate 转 LocalDate
                    (Converter<Date, LocalDate>) source -> 
                            source.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
            ));
        }
    
        @Bean
        public MongoTemplate mongoTemplate(MongoDatabaseFactory factory, MappingMongoConverter converter) {
            // 去除写入Mongo时自动生成的_class字段
            converter.setTypeMapper(new DefaultMongoTypeMapper(null));
            return new MongoTemplate(factory, converter);
        }
    }
    
  3. (可选)配置全局命名策略省略@Field注解
    如果不想给每个实体字段加@Field指定下划线名称,可以在配置中添加全局驼峰转下划线的命名规则,自动完成Java驼峰字段和Mongo下划线字段的映射:

    @Bean
    public MongoMappingContext mongoMappingContext(MongoCustomConversions conversions) {
        MongoMappingContext context = new MongoMappingContext();
        // 全局驼峰转下划线
        context.setFieldNamingStrategy(property -> {
            char[] nameChars = property.getName().toCharArray();
            StringBuilder fieldName = new StringBuilder();
            for (char c : nameChars) {
                if (Character.isUpperCase(c)) {
                    fieldName.append('_').append(Character.toLowerCase(c));
                } else {
                    fieldName.append(c);
                }
            }
            return fieldName.toString();
        });
        context.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
        return context;
    }
    

修改完成后重启服务,再次发起Postman请求即可正常返回带值的业务数据。

内容的提问来源于stack exchange,提问作者Deep

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 22:54:10