使用配置文件初探

(一).最简单的配置

文件类型支持两种,yml和properties,springboot使用配置文件很简单,只需在resources目录下创建application.properties文件,编码最好选择utf-8,统一编码格式,
创建一个测试配置项

test.value=test

使用@vaule注解在程序中引用test.value的值

@Value("${test.value}")
private String testValue;

这样项目运行后,”test”就自动注入给了testValue

(二).使用Bean来管理多个配置项

如果我们的配置项有多个,springboot官方推荐使用java bean来进行管理。

再增加一个配置项

test.value1=test1
@Value("${test.value1}")
private String testValue1;

创建一个java bean 里面做配置项的注入
ConfigBean.java

package com.my.webapp.config;

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

/**
 * 配置文件中的Bean管理
 */
@Component
@ConfigurationProperties(prefix = "test")
public class ConfigBean {
    private String value;

    private String value1;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getValue1() {
        return value1;
    }

    public void setValue1(String value1) {
        this.value1 = value1;
    }
}

使用@ConfigurationProperties注解,同时可以加上前缀”test”,这样test.value,test.value1分别注入给了value和value1
在代码中使用

@Autowired
private ConfigBean configBean;
logger.info("test.value: "+configBean.getValue());

(三).创建多环境配置文件

在实际企业开发中我们的环境有多种,不可能仅仅application.properies就能满足使用,比如开发,测试,生产。不同环境下需要切换不同的配置文件,因此可以配合maven进行配置文件的切换
创建三套配置文件,并分别在三个文件设置test.value和test.value1不同的值
application-test.properties

test.value=test
test.value1=test1

application-dev.properties

test.value=dev
test.value1=dev1

application-prod.properties

test.value=prod
test.value1=prod1

再通过maven选配指定配置参数
web项目module对应pom文件下进行修改
pom.xml

<!--maven定义生效的配置
        三种环境 test dev prod
        激活方式 1.<activeByDefault> 
                2.mvn命令 -P test|dev|prod
    -->
    <profiles>
        <profile>
            <id>test</id>
            <properties>
                <profileActive>test</profileActive>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
    </profiles>
    <build>
        <finalName>webapp-controller</finalName>
        <!--设置资源文件-->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <!--排除的资源文件-->
                <excludes>
                    <exclude>application.properties</exclude>
                    <exclude>application-*.properties</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <!--包含的资源文件-->
                <includes>
                    <include>application.properties</include>
                    <include>application-${profileActive}.properties</include>
                </includes>
            </resource>
        </resources>

设置属性配置三种环境 profile的选择可以在执行maven命令时进行指定,当我们编译打包时

Mvn -f clean package -P dev -Dmaven.test.skip=true;

-P参数即可指定,当前选择的是dev。则id为dev的配置生效

如果我们不指定则默认使用指定了为true的配置。

最后我们还需要在application.properties文件中配置一项

spring.profiles.active=@profileActive@

该文件可以获取到maven中配置的的属性值,使用方式为@属性名@,springboot根据application-@profileActive@.properties加载具体的配置文件,maven中默认是test 则默认加载application-test.properties文件了。

(四).对配置文件中的指定配置项进行加密

参考链接:spring、spring-boot配置文件属性内容加解密

由于配置文件中的配置项包含很多敏感数据,比如数据库用户密码。如果我们需要对该属性进行加密,并且程序能够正常解析。

这里需要用到国外大牛写的一个java实现的安全框架:jaspyt

在pom文件中加入该依赖

<dependency>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-spring-boot-starter</artifactId>
        <version>1.14</version>
</dependency>

这样我们程序就具有了对配置文件进行加密解密的功能了,具体怎么使用请参考以上别人的链接该框架默认使用的加密算法为PBEWithMD5AndDES,我们可以自定义加密算法进行加密解密

这里使用了DES加密算法

DESUtil.java

package com.cdvcredit.common.utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.SecureRandom;
import java.util.Base64;


public class DESUtil {

    public static String encrypt(String plainText, String privateKey) {

        try {
            KeyGenerator keygen = KeyGenerator.getInstance("DES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(privateKey.getBytes());

            keygen.init(56, secureRandom);
            SecretKey secretKey = keygen.generateKey();

            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            byte[] cipherBytes = cipher.doFinal(plainText.getBytes("utf-8"));
            byte[] plainTextBytes = Base64.getEncoder().encode(cipherBytes);

            return new String(plainTextBytes, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    public static String decrypt(String cipherText, String privateKey) {
        try {
            KeyGenerator keygen = KeyGenerator.getInstance("DES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(privateKey.getBytes());

            keygen.init(56, secureRandom);
            SecretKey secretKey = keygen.generateKey();

            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);

            byte[] cipherTextBytes = Base64.getDecoder().decode(cipherText.getBytes("utf-8"));
            byte[] cipherBytes = cipher.doFinal(cipherTextBytes);

            return new String(cipherBytes, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

接下来则是用自定义加密算法替换默认加密解密算法
jaspyt默认通过StringEncryptor进行加密解密,我们只需要覆盖该实现即可
编写一个实现StringEncryptor接口的类,覆写encrypt()和decrypt()方法

PropertiesEncryptor.java

package com.cdvcredit.api.app.component;

import com.cdvcredit.common.utils.DESUtil;
import com.cdvcredit.common.utils.FileUtil;
import org.jasypt.encryption.StringEncryptor;

import java.net.URL;

public class PropertiesEncryptor implements StringEncryptor {

    private String privateKey;

    private static String privateKeyFileName = "properties_key.txt";

    public PropertiesEncryptor() {
        super();
        this.privateKey = getPrivateKeyString();

    }

    @Override
    public String encrypt(String s) {
        return DESUtil.encrypt(s, privateKey);
    }

    @Override
    public String decrypt(String s) {
        return DESUtil.decrypt(s, privateKey);
    }

    private String getPrivateKeyString() {
        ClassLoader classLoader = getClass().getClassLoader();
        URL url = classLoader.getResource(privateKeyFileName);
        if (url == null) {
            return null;
        }
        System.out.println(url.getFile());
        return FileUtil.readToString(url.getFile());
    }
}

在这里加解密所需要的密钥暂时是存放在一个本地文件”properties_key.txt”中,getPrivateKeyString()方法是从该文件中取出该密钥

FileUtil.java

package com.cdvcredit.common.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

public class FileUtil {

    public static String readToString(String pathName) {
        File file = new File(pathName);
        StringBuilder result = new StringBuilder();
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String s = null;
            while ((s = br.readLine()) != null) {
                result.append(s);
            }
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return result.toString();
    }

}

最后通过java config让spring启动加载我们覆盖后的加解密类PropertiesEncryptor

PropertiesEncryptorConfig.java

package com.cdvcredit.api.app.component;

import org.jasypt.encryption.StringEncryptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class PropertiesEncryptorConfig {
    @Bean(name = "jasyptStringEncryptor")
    public StringEncryptor stringEncryptor() {
        return new PropertiesEncryptor();

    }
}

这里需要注意jaspyt根据bean名”jasyptStringEncryptor”去查找加解密工具

对明文如何进行加密?

我们可以编写一个测试方法

@Autowired
    private StringEncryptor jasyptStringEncryptor;
    @Test
    public void encryptTest(){
        System.out.println(jasyptStringEncryptor.encrypt("dev"));
    }

执行后得到KbYBe+WcTEM=

我们在配置文件中加上该属性值,格式为ENC(‘密文’),这样的格式才会被jaspyt框架识别并解密

application-dev.properties

test.value=ENC(KbYBe+WcTEM=)
test.value1=dev1

然后在代码中使用该test.value属性,即可正确解析到。
参考:
spring、spring-boot配置文件属性内容加解密