赤峰网站制作公司,全球最顶尖的设计公司,河北房地产网站建设,网站建设最新时讯MongoDB推荐使用ObjectId作为主键#xff0c;但国内的开发都知道#xff0c;事情往往不如人所愿#xff0c;当我们真的出现了“_id”主键的类型为String时#xff0c;且还必须想用mongoTemplate.findOne或findList时#xff0c;直接使用该方法会导致查询结果为空。
因为m…MongoDB推荐使用ObjectId作为主键但国内的开发都知道事情往往不如人所愿当我们真的出现了“_id”主键的类型为String时且还必须想用mongoTemplate.findOne或findList时直接使用该方法会导致查询结果为空。
因为mongoTemplate会在查询的时候将主键转换为ObjectId。
实际上这一步转换是MappingMongoConverter中做的源码如下 /*** Converts the given raw id value into either {link ObjectId} or {link String}.** param id can be {literal null}.* param targetType must not be {literal null}.* return {literal null} if source {literal id} is already {literal null}.* since 2.2*/
Nullabledefault Object convertId(Nullable Object id, Class? targetType) {if (id null || ClassUtils.isAssignableValue(targetType, id)) {return id;}if (ClassUtils.isAssignable(ObjectId.class, targetType)) {if (id instanceof String) {if (ObjectId.isValid(id.toString())) {return new ObjectId(id.toString());}// avoid ConversionException as convertToMongoType will return String anyways.return id;}}try {return getConversionService().canConvert(id.getClass(), targetType)? getConversionService().convert(id, targetType): convertToMongoType(id, (TypeInformation?) null);} catch (ConversionException o_O) {return convertToMongoType(id,(TypeInformation?) null);}}
注意示例版本为spring-data-mongodb:3.3.5一些更古早的版本如2.1.9需要重写其他部分如果有人需要请留言我会抽时间补充但鉴于之前的版本有比较重大的漏洞所以推荐升级版本。 if (ObjectId.isValid(id.toString())) { return new ObjectId(id.toString()); }
这段就是mongoTemplate将String转换为ObjectId的步骤。
所以我们要做的就是重写这部分并且替换掉原有的
1、新建一个Converter
public class MyMongoConverter extends MappingMongoConverter {public MyMongoConverter(DbRefResolver dbRefResolver, MappingContext? extends MongoPersistentEntity?, MongoPersistentProperty mappingContext) {super(dbRefResolver, mappingContext);}Overridepublic Object convertId(Nullable Object id, Class? targetType) {if (id null || ClassUtils.isAssignableValue(targetType, id)) {return id;}if (ClassUtils.isAssignable(ObjectId.class, targetType)) {if (id instanceof String) {return id;}}try {return getConversionService().canConvert(id.getClass(), targetType)? getConversionService().convert(id, targetType): convertToMongoType(id, (TypeInformation?) null);} catch (ConversionException o_O) {return convertToMongoType(id,(TypeInformation?) null);}}
}
2、在构建MongoTemplate时用我们自己写的替换
MongoTemolate mongoTemplate new MongoTemplate(mongoDbFactory(), getDefaultMongoConverter(mongoDbFactory()))protected static MongoConverter getDefaultMongoConverter(MongoDatabaseFactory factory) {DbRefResolver dbRefResolver new DefaultDbRefResolver(factory);MongoCustomConversions conversions new MongoCustomConversions(Collections.emptyList());MongoMappingContext mappingContext new MongoMappingContext();mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());mappingContext.afterPropertiesSet();MyMongoConverter converter new MyMongoConverter(dbRefResolver, mappingContext);converter.setCustomConversions(conversions);converter.afterPropertiesSet();converter.setTypeMapper(new DefaultMongoTypeMapper(null));return converter;}/*** return {link MongoDatabaseFactory}*/protected MongoDatabaseFactory mongoDbFactory() {ServerAddress serverAddress new ServerAddress(host, port);MongoClientSettings.Builder setting MongoClientSettings.builder().applyToClusterSettings(builder - builder.hosts(Collections.singletonList(serverAddress))).retryWrites(false);if (ObjectUtil.isNotEmpty(username)) {MongoCredential credential MongoCredential.createCredential(username, authenticationDatabase, password.toCharArray());setting.credential(credential);}MongoClient mongoClient MongoClients.create(setting.build());return new SimpleMongoClientDatabaseFactory(mongoClient, database);}
host,port,username,authenticationDatabase,password,database
分别为MongoDB的地址端口号用户名认证数据库密码数据库名