• springboot整合mongodb问题1-Decimal128和BigDecimal的转换之mongodb转换器使用(转)


    转自:https://blog.csdn.net/weixin_41792559/article/details/79575524

    1.Decimal128的了解
    由于mongodb4.3以上新加了Decimal128类型。Decimal128类型对小数给了最好的支持,而double类型对小数存在精度的问题。个人觉得Decimal128还是不错的。但是我测试发现spring-data-mongodb 1.*和现在的spring-data-mongodb2.0.5目前不支持Decimal128自动转换为java的BigDecimal类型。
    异常: No converter found capable of converting from type [org.bson.types.Decimal128] to type [java.math.BigDecimal]
    大概就是描述:没有Decimal128转换成BigDecimal的转换器。

    2.访问mongodb方式:spring-data-mongodb的MongoTemplate。
    目前先以spring-data-mongodb的MongoTemplate方式为案例。之后我会增加mongodb原始的dom处理方式,以及spring-boot-starter-data-mongodb下开启了对Repository的支持方式进行测试一下。(进行了测试)
    代码:https://github.com/topsnowwolf/mongodbit

    3.如何解决Decimal128,BigDecimal的类型转换问题呢?
    思路:没有转换器我们新加一个转换。如何新加呢?增加之后如何配置呢?这就是重点了。
    首先spring增加类型转换器有 三种方式。

    1.实现GenericConverter接口

    2.实现ConverterFactory接口

    3.实现Converter接口

    这三种方式分别如何实现类型转换器,我就不多说了。网上很多例子。

    下面我就以实现Converter接口方式的来实现。

    自定义类型转换器:

    package com.wolf.mongodbit.converter;
     
    import org.bson.types.Decimal128;
    import org.springframework.core.convert.converter.Converter;
    import org.springframework.data.convert.ReadingConverter;
    import org.springframework.data.convert.WritingConverter;
     
    import java.math.BigDecimal;
     
    @ReadingConverter
    @WritingConverter
    public class BigDecimalToDecimal128Converter implements Converter<BigDecimal, Decimal128> {
         
        public Decimal128 convert(BigDecimal bigDecimal) {
            return new Decimal128(bigDecimal);
        }
        
    }
    package com.wolf.mongodbit.converter;
     
    import org.bson.types.Decimal128;
    import org.springframework.core.convert.converter.Converter;
    import org.springframework.data.convert.ReadingConverter;
    import org.springframework.data.convert.WritingConverter;
     
    import java.math.BigDecimal;
     
    @ReadingConverter
    @WritingConverter
    public class Decimal128ToBigDecimalConverter implements Converter<Decimal128, BigDecimal> {
     
        public BigDecimal convert(Decimal128 decimal128) {
            return decimal128.bigDecimalValue();
        }
        
        
     
    }

    下面我就分析一下MongoTemplate的源码。

    我们先带着问题去看。我们增加了转换器,这个转换器是给访问mongodb用的,那肯定是给MongoTemplate设置新的转换器了。

    打开MongoTemplate这个类,果然如此。MongoTemplate的构造方法中就有一个参数是设置类型转换器的。看到希望了。哈哈!

        public MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverter) {
            this.writeConcernResolver = DefaultWriteConcernResolver.INSTANCE;
            this.writeResultChecking = WriteResultChecking.NONE;
            Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null!");
            this.mongoDbFactory = mongoDbFactory;
            this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
            this.mongoConverter = mongoConverter == null ? getDefaultMongoConverter(mongoDbFactory) : mongoConverter;
            this.queryMapper = new QueryMapper(this.mongoConverter);
            this.updateMapper = new UpdateMapper(this.mongoConverter);
            this.mappingContext = this.mongoConverter.getMappingContext();
            if (null != this.mappingContext && this.mappingContext instanceof MongoMappingContext) {
                this.indexCreator = new MongoPersistentEntityIndexCreator((MongoMappingContext)this.mappingContext, mongoDbFactory);
                this.eventPublisher = new MongoMappingEventPublisher(this.indexCreator);
                if (this.mappingContext instanceof ApplicationEventPublisherAware) {
                    ((ApplicationEventPublisherAware)this.mappingContext).setApplicationEventPublisher(this.eventPublisher);
                }
            }
     
        }

    最终发现MongoConverter是一个接口。那一定有实现它的类。查一下api发现,抽象的类AbstractMongoConverter,最后是MappingMongoConverter类。此时就会发现AbstractMongoConverter类中有setCustomConversions设置自定义类型转换器的set方法。现在兴奋了吧!!!

    现在大概的思路就是通过创建一个MappingMongoConverter对象,将定义的类型转换器调用setCustomConversions方法进行注册。最后调用MongoTemplate的构造方法得到MongoTemplate对象。

    废话不多说上代码:

    自定义一个配置类:

    package com.wolf.mongodbit.config;
     
    import com.mongodb.MongoClient;
    import com.mongodb.MongoClientURI;
    import com.wolf.mongodbit.converter.BigDecimalToDecimal128Converter;
    import com.wolf.mongodbit.converter.Decimal128ToBigDecimalConverter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.mongodb.MongoDbFactory;
    import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
    import org.springframework.data.mongodb.core.MongoTemplate;
    import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
    import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
    import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
    import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
    import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
     
    import java.util.ArrayList;
    import java.util.List;
    @Configuration
    public class MongodbConfig extends AbstractMongoConfiguration{
        private String dbName = "wolf";
        @Override
        public MongoClient mongoClient() {
            MongoClient mongoClient = new MongoClient();
            return mongoClient;
        }
     
        @Override
        protected String getDatabaseName() {
            return dbName;
        }
        @Bean
        public MappingMongoConverter mappingMongoConverter() throws Exception {
            DefaultDbRefResolver dbRefResolver = new DefaultDbRefResolver(this.dbFactory());
            MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, this.mongoMappingContext());
            List<Object> list = new ArrayList<>();
            list.add(new BigDecimalToDecimal128Converter());//自定义的类型转换器
            list.add(new Decimal128ToBigDecimalConverter());//自定义的类型转换器
            converter.setCustomConversions(new MongoCustomConversions(list));
            return converter;
        }
        @Bean
        public MongoDbFactory dbFactory() throws Exception {
            return new SimpleMongoDbFactory(new MongoClientURI("mongodb://localhost:27017/wolf"));
        }
        @Bean
        public MongoMappingContext mongoMappingContext() {
            MongoMappingContext mappingContext = new MongoMappingContext();
            return mappingContext;
        }
        @Bean
        public MongoTemplate mongoTemplate() throws Exception {
            return new MongoTemplate(this.dbFactory(), this.mappingMongoConverter());
        }
    }

    实体类:

    package com.wolf.mongodbit.entity.mongodb;
     
    import lombok.Data;
     
    @Data
    public class Address {
        private String aCode;
        private String add;
    }
    package com.wolf.mongodbit.entity.mongodb;
     
    import lombok.Data;
    import org.bson.types.ObjectId;
    import org.springframework.data.mongodb.core.mapping.Document;
     
    import java.util.Date;
     
     
    @Document(collection="blacklist")
    @Data
    public class Blacklist {
        private ObjectId objectId;
        private String username;
        private String userid;
        private String blacktype;
        private String status;
        private Date update;
        private Date indate;
        private Address address;
        private Comments comments;
    }
    package com.wolf.mongodbit.entity.mongodb;
     
    import lombok.Data;
     
    import java.math.BigDecimal;
    @Data
    public class Comments {
        private String cause;
        private String desc;
        private BigDecimal money;
    }

    测试的controller:

    package com.wolf.mongodbit.controller;
     
     
    import com.wolf.mongodbit.entity.mongodb.Blacklist;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.mongodb.core.MongoTemplate;
    import org.springframework.data.mongodb.core.query.Query;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
     
    import java.util.List;
     
    import static org.springframework.data.mongodb.core.query.Criteria.where;
    import static org.springframework.data.mongodb.core.query.Query.query;
     
    @RestController
    @RequestMapping("/mongodb")
    public class BlackListController {
        private final static Logger logger = LoggerFactory.getLogger(BlackListController.class);
        @Autowired
        private MongoTemplate mongoTemplate;
        @PostMapping("/check")
        private Blacklist checkBlack(Blacklist blackList){
            List<Blacklist> list = mongoTemplate.find(query(where("userid").is(blackList.getUserid())), Blacklist.class);
            logger.info("springboot+mongodb:size={}",list.size());
            if(list.size()>0)
                return list.get(0);
            return null;
        }
    }

    pom配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
     
        <groupId>com.wolf</groupId>
        <artifactId>mongodbit</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
     
        <name>mongodbit</name>
        <description>Demo project for Spring Boot</description>
     
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.0.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
     
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
     
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
     
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
     
            <!--lombok自动生成实体类get/set方法 start-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
            <!--lombok自动生成实体类get/set方法 end-->
            
            <!--mongodb引入 start -->
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-mongodb</artifactId>
            </dependency>
            <!--
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-mongodb</artifactId>
            </dependency>
            -->
            <!--mongodb引入 end -->
        </dependencies>
     
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
     
     
    </project>

    yml配置文件:

    #访问项目的url前缀
    server:
      servlet:
        context-path: /mongodb

    mongodb的测试数据:

    var blacklist1 = {
            "username" : "snowwolf",
            "userid" : "2018001014344",
            "address" : {
                    "aCode" : "0020",
                    "add" : "广州"
            },
            "certificate":{
                "certificateid":"20018554111134",
                "certificatetype":"01",
                "desc":"学生证"
            },
           "blacktype" : "01",
           "comments":{
                "cause":"01",
                "desc":"逾期欠费",
                "money":NumberDecimal("18889.09")
           },
           "status":"01",
           "update" : ISODate("2017-12-06T04:26:18.354Z"),
           "indate" : ISODate("2017-12-06T04:26:18.354Z")
            
    };
    var blacklist2 = {
            "username" : "lison",
            "userid" : "2018001014345",
            "address" : {
                    "aCode" : "0075",
                    "add" : "深圳"
            },
            "certificate":{
                "certificateid":"20018554111134",
                "certificatetype":"02",
                "desc":"护照"
            },
           "blacktype" : "01",
           "comments":{
                "cause":"02",
                "desc":"恶意欠费",
                "money":NumberDecimal("188890.00")
           },
           "status":"01",
           "update" : ISODate("2016-01-06T04:26:18.354Z"),
           "indate" : ISODate("2015-12-06T04:26:18.354Z")
            
    };
    var blacklist3 = {
            "username":"tom",
            "userid":"2018001014346",
            "address":{
                    "aCode" : "0020",
                    "add" : "广州"
            },
            "certificate":{
                "certificateid":"20018554111136",
                "certificatetype":"01",
                "desc":"学生证"
            },
           "blacktype":"01",
           "comments":{
                "cause":"03",
                "desc":"公安机关确定的涉嫌短信欺诈、诈骗等犯罪行为的用户"
           },
           "status":"01",
           "update":ISODate("2017-12-06T04:26:18.354Z"),
           "indate":ISODate("2017-12-06T04:26:18.354Z")
            
    };
     
    db.blacklist.insert(blacklist1);
    db.blacklist.insert(blacklist2);
    db.blacklist.insert(blacklist3);
     

    在postman中测试:

    结果完美!

    时间有限,有些地方可能不是很完美!不足之处请大牛指出,谢谢!

    有需要代码的我之后将会发布到git上!

    https://github.com/topsnowwolf/mongodbit

  • 相关阅读:
    设计模式-创建型-原型模式
    设计模式-创建型-抽象工厂模式
    设计模式-创建型-工厂模式
    设计模式-创建型-单例模式
    css3技巧属性之text-overflow
    bootstrap如何自定义5等分
    LeetCode-64-最小路径和
    LeetCode-62-不同路径
    LeetCode-5-最长回文子串
    LeetCode-98-验证二叉搜索树
  • 原文地址:https://www.cnblogs.com/muxi0407/p/11703316.html
Copyright © 2020-2023  润新知