• 使用spring boot访问mongodb数据库


    一. spring boot中传参的方法

     1、自动化配置

    spring Boot 对于开发人员最大的好处在于可以对 Spring 应用进行自动配置。Spring Boot 会根据应用中声明的第三方依赖来自动配置 Spring 框架,而不需要进行显式的声明。比如
    当声明了对 HSQLDB 的依赖时,Spring Boot 会自动配置成使用 HSQLDB 进行数据库操作。

    Spring Boot 推荐采用基于 Java 注解的配置方式,而不是传统的 XML。只需要在主配置 Java 类上添加“@EnableAutoConfiguration”注解就可以启用自动配置。Spring Boot 的自动配置
    功能是没有侵入性的,只是作为一种基本的默认实现。开发人员可以通过定义其他 bean 来替代自动配置所提供的功能。比如当应用中定义了自己的数据源 bean 时,自动配置所提供的
    HSQLDB 就不会生效。这给予了开发人员很大的灵活性。既可以快速的创建一个可以立即运行的原型应用,又可以不断的修改和调整以适应应用开发在不同阶段的需要。可能在应用最开始的时
    候,嵌入式的内存数据库(如 HSQLDB)就足够了,在后期则需要换成 MySQL 等数据库。Spring Boot 使得这样的切换变得很简单。

    2、外部化的配置

    在应用中管理配置并不是一个容易的任务,尤其是在应用需要部署到多个环境中时。通常会需要为每个环境提供一个对应的属性文件,用来配置各自的数据库连接信息、服务器信息和第
    三方服务账号等。通常的应用部署会包含开发、测试和生产等若干个环境。不同的环境之间的配置存在覆盖关系。测试环境中的配置会覆盖开发环境,而生产环境中的配置会覆盖测试环境。
    Spring 框架本身提供了多种的方式来管理配置属性文件。Spring 3.1 之前可以使用 PropertyPlaceholderConfigurer。Spring 3.1 引入了新的环境(Environment)和概要信息(Profile)
    API,是一种更加灵活的处理不同环境和配置文件的方式。不过 Spring 这些配置管理方式的问题在于选择太多,让开发人员无所适从。Spring Boot 提供了一种统一的方式来管理应用的配置
    ,允许开发人员使用属性文件、YAML 文件、环境变量和命令行参数来定义优先级不同的配置值。

    Spring Boot 所提供的配置优先级顺序比较复杂。按照优先级从高到低的顺序,具体的列表如下所示。

    (1) 命令行参数
    (2) java:comp/env 里的JNDI属性
    (3) JVM系统属性
    (4) 操作系统环境变量
    (5) 随机生成的带 random.* 前缀的属性(在设置其他属性时,可以引用它们,比如 ${random.
    long} )
    (6) 应用程序以外的application.properties或者appliaction.yml文件
    (7) 打包在应用程序内的application.properties或者appliaction.yml文件
    (8) 通过 @PropertySource 标注的属性源
    (9) 默认属性

    这个列表按照优先级排序,也就是说,任何在高优先级属性源里设置的属性都会覆盖低优先级的相同属性。例如,命令行参数会覆盖其他属性源里的属性。

    application.properties和application.yml文件能放在以下四个位置。
    (1) 外置,在相对于应用程序运行目录的/config子目录里。
    (2) 外置,在应用程序运行的目录里。
    (3) 内置,在config包内。
    (4) 内置,在Classpath根目录。
    同样,这个列表按照优先级排序。也就是说,/config子目录里的application.properties会覆盖应用程序Classpath里的application.properties中的相同属性。
    此外,如果我们在同一优先级位置同时有application.properties和application.yml,那么application.yml里的属性会覆盖application.properties里的属性。
    命令行参数

    通过Java -jar app.jar –name=”Spring” –server.port=9090方式来传递参数。

    SpringApplication 类默认会把以“–”开头的命令行参数转化成应用中可以使用的配置参数,如 “–name=Alex” 会设置配置参数 “name” 的值为 “Alex”.

    可以使用的参数可以是我们自己定义的,也可以是Spring Boot中默认的参数。

    注意:命令行参数在app.jar的后面!

    可以通过SpringApplication.setAddCommandLineProperties(false)禁用命令行配置。
    Java系统属性

    注意Java系统属性位置java -Dname=”isea533″ -jar app.jar,可以配置的属性都是一样的,优先级不同。

    例如java -Dname=”isea533″ -jar app.jar –name=”Spring!”中name值为Spring.

    有些系统,关于一些数据库或其他第三方账户等信息,由于安全问题,其配置并不会提前配置在项目中暴露给开发人员。
    对于这种情况,我们在运行程序的时候,可以通过参数指定一个外部配置文件。
    以 demo.jar 为例,方法如下: java -jar demo.jar –spring.config.location=/opt/config/application.properties

    其中文件名随便定义,无固定要求。

    RandomValuePropertySource

    RandomValuePropertySource 可以用来生成测试所需要的各种不同类型的随机值,从而免去了在代码中生成的麻烦。RandomValuePropertySource 可以生成数字和字符串。数字的类型
    包含 int 和 long,可以限定数字的大小范围。以“random.”作为前缀的配置属性名称由 RandomValuePropertySource 来生成:

    系统中用到随机数的地方,例如 使用 RandomValuePropertySource 生成的配置属性:

    user.id=${random.value}
    user.count=${random.int}
    user.max=${random.long}
    user.number=${random.int(100)}
    user.range=${random.int[100, 1000]

    random.int*支持value参数和,max参数,当提供max参数的时候,value就是最小值

    3. 读取属性

    读取application.yml中的localhost配置的值

    package com.gwc.context;

    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;

    /**
    * Created by gwcheng on 2017/3/6.
    */
    @Component
    @ConfigurationProperties
    public class SystemProperties
    {
    private String localhost;

    public String getLocalhost() {
    return localhost;
    }

    public void setLocalhost(String localhost) {
    this.localhost = localhost;
    }
    }

    还可以在Bean中使用

    @Value(“${server.port}”)
    private String serverPort;

    来读取配置文件中的属性值

    当前目录的“/config”子目录。
    当前目录。
    classpath 中的“/config”包。
    classpath

    上面的顺序也表示了该位置上包含的属性文件的优先级。优先级按照从高到低的顺序排列。 即:/config优先于classpath根目录

    可以通过“spring.config.name”配置属性来指定不同的属性文件名称。也可以通过“spring.config.location”来添加额外的属性文件的搜索路径。如果应用中包含多个 profile,
    可以为每个 profile 定义各自的属性文件,按照“application-{profile}”来命名。

    @PropertySource优先级比较

    这个注解可以指定具体的属性配置文件,优先级比较低。

    SpringApplication.setDefaultProperties

    例如:

    SpringApplication application = new SpringApplication(Application.class);
    Map<String, Object> defaultMap = new HashMap<String, Object>();
    defaultMap.put(“name”, “Isea-Blog”);
    //还可以是Properties对象
    application.setDefaultProperties(defaultMap);
    application.run(args);
    应用程序使用属性@Value(“${xxx}”)

    对于配置属性,可以在代码中通过“@Value”来使用,如:

    @RestController
    @EnableAutoConfiguration
    public class Application {
    @Value(“${name}”)
    private String name;
    @RequestMapping(“/”)
    String home() {
    return String.format(“Hello %s!”, name);
    }
    }

    变量 name 的值来自配置属性中的“name”属性。

    比如application.properties有 port=8081

    @Value(“${port:8082}”)
    private String port;

    即可获取8081这个值

    属性占位符

    例如:

    app.name=MyApp

    app.description=${app.name} is a Spring Boot application

    可以在配置文件中引用前面配置过的属性(优先级前面配置过的这里都能用)。

    通过如${app.name:默认名称}方法还可以设置默认值,当找不到引用的属性时,会使用默认的属性。

    由于${}方式会被Maven处理。如果你pom继承的spring-boot-starter-parent,Spring Boot 已经将maven-resources-plugins默认的${}方式改为了@ @方式,例如@name@。

    如果你是引入的Spring Boot,你可以修改使用其他的分隔符

    通过属性占位符还能缩短命令参数

    例如修改web默认端口需要使用–server.port=9090方式,如果在配置中写上:

    server.port=${port:8080}

    那么就可以使用更短的–port=9090,当不提供该参数的时候使用默认值8080。

    属性名匹配规则

    例如有如下配置对象:

    @Component
    @ConfigurationProperties(prefix=”person”)
    public class ConnectionSettings {
    private String firstName;
    }

    firstName可以使用的属性名如下:

    person.firstName,标准的驼峰式命名
    person.first-name,虚线(-)分割方式,推荐在.properties和.yml配置文件中使用
    PERSON_FIRST_NAME,大写下划线形式,建议在系统环境变量中使用

    属性验证

    可以使用JSR-303注解进行验证,例如:

    @Component
    @ConfigurationProperties(prefix=”connection”)
    public class ConnectionSettings {

    @NotNull
    private InetAddress remoteAddress;

    // … getters and setters

    }

    这些内容已经足够本文使用来做一个可以配置的连接mongodb的程序了, 网络上还有更多的介绍关于spring boot属性文件的, 大家可以去百度搜搜。

    二. 改造 spring boot的mongodb项目

    1. 改造中遇到的一个问题

    经过上面的关于spring boot的摸索, 编写了如下一个代码

    package cn.iigrowing.study.mongodb;
    
    ... 代码详情后面会提供
    
    @Component    // 这个很重要, 否则类不会被扫描
    public class MyMongoClient {
     @Bean   // 生命这个是一个bean
     @ConditionalOnMissingBean(MongoClient.class)   // 说明这个替换那个默认的
     public MongoClient getMongodbClients() {
     
     ..... 
     
     MongoCredential credential = MongoCredential.createMongoCRCredential(myUsername, database, myPassword.toCharArray());
     MongoClient client = new MongoClient(addresses, Arrays.asList(credential));
     return client;
     }
     
     // mongodb://192.168.128.189:27017,192.168.128.132:27017,192.168.128.133:27017/mytest03
     @Value("${mongodb.uri}")    // 获取uri然后进行解析
     private String myUri;
     
     @Value("${mongodb.username}")  // 获取用户名
     private String myUsername;
     
     @Value("${mongodb.password}")  // 获取密码
     private String myPassword;
    
    }

    然后启动程序, 最后报如下异常:

    java.lang.IllegalStateException: Failed to execute CommandLineRunner
     at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:779)
     at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:760)
     at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:747)
     at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162)
     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151)
     at cn.iigrowing.study.mongodb.Application.main(Application.java:14)
    Caused by: org.springframework.data.mongodb.UncategorizedMongoDbException: Command failed with error 13: 'not authorized on test to execute command { insert: "customer", ordered: true, documents: [ { _id: ObjectId('5955fad2bb844c23906eff87'), _class: "cn.iigrowing.study.mongodb.Customer", firstName: "Alice", lastName: "Smith", address: { aa: "100000", ddd: "20000" } } ] }' on server node3.iigrowing.cn:27017. The full response is { "ok" : 0.0, "errmsg" : "not authorized on test to execute command { insert: "customer", ordered: true, documents: [ { _id: ObjectId('5955fad2bb844c23906eff87'), _class: "cn.iigrowing.study.mongodb.Customer", firstName: "Alice", lastName: "Smith", address: { aa: "100000", ddd: "20000" } } ] }", "code" : 13 }; nested exception is com.mongodb.MongoCommandException: Command failed with error 13: 'not authorized on test to execute command { insert: "customer", ordered: true, documents: [ { _id: ObjectId('5955fad2bb844c23906eff87'), _class: "cn.iigrowing.study.mongodb.Customer", firstName: "Alice", lastName: "Smith", address: { aa: "100000", ddd: "20000" } } ] }' on server node3.iigrowing.cn:27017. The full response is { "ok" : 0.0, "errmsg" : "not authorized on test to execute command { insert: "customer", ordered: true, documents: [ { _id: ObjectId('5955fad2bb844c23906eff87'), _class: "cn.iigrowing.study.mongodb.Customer", firstName: "Alice", lastName: "Smith", address: { aa: "100000", ddd: "20000" } } ] }", "code" : 13 }
     at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java:107)
     at org.springframework.data.mongodb.core.MongoTemplate.potentiallyConvertRuntimeException(MongoTemplate.java:2135)
     at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:481)
     at org.springframework.data.mongodb.core.MongoTemplate.insertDBObject(MongoTemplate.java:1046)
     at org.springframework.data.mongodb.core.MongoTemplate.doInsert(MongoTemplate.java:855)
     at org.springframework.data.mongodb.core.MongoTemplate.insert(MongoTemplate.java:796)
     at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:80)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     at java.lang.reflect.Method.invoke(Unknown Source)
     at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504)
     at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489)
     at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
     at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
     at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
     at com.sun.proxy.$Proxy45.save(Unknown Source)
     at cn.iigrowing.study.mongodb.Application.run(Application.java:28)
     at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:776)
     ... 6 common frames omitted
    Caused by: com.mongodb.MongoCommandException: Command failed with error 13: 'not authorized on test to execute command { insert: "customer", ordered: true, documents: [ { _id: ObjectId('5955fad2bb844c23906eff87'), _class: "cn.iigrowing.study.mongodb.Customer", firstName: "Alice", lastName: "Smith", address: { aa: "100000", ddd: "20000" } } ] }' on server node3.iigrowing.cn:27017. The full response is { "ok" : 0.0, "errmsg" : "not authorized on test to execute command { insert: "customer", ordered: true, documents: [ { _id: ObjectId('5955fad2bb844c23906eff87'), _class: "cn.iigrowing.study.mongodb.Customer", firstName: "Alice", lastName: "Smith", address: { aa: "100000", ddd: "20000" } } ] }", "code" : 13 }
     at com.mongodb.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:115)
     at com.mongodb.connection.WriteCommandProtocol.receiveMessage(WriteCommandProtocol.java:268)

    为了查明原因仔细检查了前文:   spring boot访问mongodb副本集方法1

    里面的访问方法, 并且运行了那个程序, 程序正确执行, 说明用户名和密码等都正确, 那到底是哪里的问题?

    最后发现两个项目的默认配置文件不同, 如下图

    spring-boot中不同配置名称造成启动问题

    spring-boot中不同配置名称造成启动问题

    原因分析, 在spring boot中 ,程序会自动扫描配置, 根据这些配置属性, 来启动一系列的相关程序, 在刚刚有问题程序中, 由于没有采用默认的spring的mongodb的配置名称, 可能造成spring boot的mongodb环境不完整,因此有问题, 然后修改配置问题后, 启动程序, 程序正确运行了。

    另外程序运行过程中有大量日志输出, 不利观察程序运行情况, 对日志进行了设置, 请参考: Spring Boot日志管理

    然后在application.properties 文件中, 添加 logging.level.root=INFO

    修改了默认的日志级别

    2. 修正后的改造

    修改应用的 application.properties 配置文件如下

    spring.data.mongodb.username=mytest03
    spring.data.mongodb.password=password
    spring.data.mongodb.uri=mongodb://192.168.128.189:27017,192.168.128.132:27017,192.168.128.133:27017/mytest03
    
    logging.level.root=INFO

    以及读取的配置文件的部分

    @Value("${spring.data.mongodb.uri}")
     private String myUri;
     
     @Value("${spring.data.mongodb.username}")
     private String myUsername;
     
     @Value("${spring.data.mongodb.password}")
     private String myPassword;

    然后从新编译了程序, 启动程序后运行正确

  • 相关阅读:
    再学梳理数据指标体系
    mac下Robot Framework-demo脚本
    Robot Framework-环境搭建
    Tensorflow学习笔记No.11
    Tensorflow学习笔记No.10
    Tensorflow学习笔记No.9
    Tensorflow学习笔记No.8
    Tensorflow学习笔记No.7
    Tensorflow学习笔记No.6
    Tensorflow学习笔记No.4.2
  • 原文地址:https://www.cnblogs.com/xhj123/p/8862635.html
Copyright © 2020-2023  润新知