[From] http://blog.csdn.net/ethanq/article/details/7333897

在我们开发当中,经常会用到spring框架来读取属性文件的属性值,然后使用占位符引用属性文件的属性值来简化配置以及使配置具有更高的灵活性和通用性。



   如下面的属性配置文件:db.properties 



   #数据库配置

   db.driver=org.postgresql.Driver

   db.url=jdbc\:postgresql\://10.166.176.127\:5432/test

   db.username=ivsadmin

   db.password=123456

   db.name=ivs

applicationContext.xml文件

[html] view
plain
 copy

  1. <context:property-placeholder location="classpath:db.properties" />
  2. <bean id="dataSource"
  3. class="com.mchange.v2.c3p0.ComboPooledDataSource"
  4. destroy-method="close">
  5. <property name="driverClass" value="${db.driver}" />
  6. <property name="jdbcUrl" value="${db.url}" />
  7. <property name="user" value="${db.username}" />
  8. <property name="password" value="${db.password}" />
  9. <property name="checkoutTimeout" value="3000" />
  10. </bean>

对于一些敏感的属性值,例如:密码属性。为了达到安全目的,我们一般会将密码进行加密。

可能希望用户看到db.properties是这样的:

#数据库配置

db.driver=org.postgresql.Driver

db.url=jdbc\:postgresql\://10.166.176.127\:5432/ivs

db.username=ivsadmin

db.password={SMC}sYNzVKgIhOprkdGhCyt81w==

db.name=ivs



这里可以看到密码属性值是加密过的,其它的属性值不变,这样就达到安全目的。这里采用的是java的3DES加密,在前面的文章中 3DES加密、解密工具类 已经有介绍了



下面开始分析下我们的需求:

  在Spring中担负对外在化应用参数的配置的是PropertyPlaceholderConfigurer和PropertyOverrideConfigurer对象,PropertyPlaceholderConfigurer实现了BeanFactoryPostProcessor接口,它能够对<bean/>中的属性值进行外在化管理。

  就像这样:

[html] view
plain
 copy

  1. <bean id="propertyConfigurer1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  2. <property name="locations">
  3. <value>WEB-INF/classes/db.properties</value>
  4. </property>
  5. </bean>

为简化PropertyPlaceholderConfigurer的使用,Spring提供了<context:property-placeholder/>元素,像applicationContext.xml文件中这样:<context:property-placeholder
location="classpath:db.properties" />

这里就很清楚了,我们只要继承PropertyPlaceholderConfigurer对象,重写PropertiesLoaderSupport接口的loadProperties方法,就可以对外部属性文件的属性值进行相关的操作了



明白了需求,下来开始我们的实现代码:



DecryptPropertyPlaceholderConfigurer.java

[java] view
plain
 copy

  1. import java.io.File;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.InputStreamReader;
  6. import java.util.Properties;
  7. import org.apache.commons.lang.StringUtils;
  8. import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
  9. import org.springframework.core.io.Resource;
  10. import com.huawei.smc.commons.constants.CommonContants;
  11. /**
  12. * <一句话功能简述>
  13. *
  14. * @author  hKF44803
  15. * @version  [版本号, 2011-12-6]
  16. * @see  [相关类/方法]
  17. * @since  [产品/模块版本]
  18. */
  19. public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer
  20. {
  21. private Resource[] locations;
  22. private DecryptPropertiesPersister propertiesPersister = new DecryptPropertiesPersister();
  23. private String fileEncoding = "utf-8";
  24. private boolean ignoreResourceNotFound = false;
  25. /**
  26. * {@inheritDoc}
  27. */
  28. @Override
  29. public void setLocations(Resource[] locations)
  30. {
  31. this.locations = locations;
  32. }
  33. /**
  34. * {@inheritDoc}
  35. */
  36. @Override
  37. public void setFileEncoding(String encoding)
  38. {
  39. this.fileEncoding = encoding;
  40. }
  41. /**
  42. * {@inheritDoc}
  43. */
  44. @Override
  45. public void setIgnoreResourceNotFound(boolean ignoreResourceNotFound)
  46. {
  47. this.ignoreResourceNotFound = ignoreResourceNotFound;
  48. }
  49. /**
  50. * {@inheritDoc}
  51. */
  52. @Override
  53. public void loadProperties(Properties props)
  54. throws IOException
  55. {
  56. // 属性文件是否为空
  57. if (this.locations != null)
  58. {
  59. // 循环读取属性文件
  60. for (int i = 0; i < this.locations.length; i++)
  61. {
  62. Resource location = this.locations[i];
  63. InputStream is = null;
  64. FileOutputStream fos = null;
  65. try
  66. {
  67. is = location.getInputStream();
  68. // 检查文件是否是XML文件
  69. if (location.getFilename().endsWith(XML_FILE_EXTENSION))
  70. {
  71. this.propertiesPersister.loadFromXml(props, is);
  72. }
  73. // 属性文件
  74. else
  75. {
  76. this.propertiesPersister.doLoad(props, new InputStreamReader(is, this.fileEncoding));
  77. String content = this.propertiesPersister.getEncryptContent();
  78. // 查找是否存在加密标识
  79. if (StringUtils.contains(content, CommonContants.DECRYPT_FLAG))
  80. {
  81. try
  82. {
  83. File file = location.getFile();
  84. fos = new FileOutputStream(file);
  85. fos.write(this.propertiesPersister.getEncryptContent().getBytes());
  86. fos.flush();
  87. }
  88. finally
  89. {
  90. if (null != fos)
  91. {
  92. fos.close();
  93. }
  94. }
  95. }
  96. }
  97. }
  98. catch (IOException ex)
  99. {
  100. if (this.ignoreResourceNotFound)
  101. {
  102. if (logger.isWarnEnabled())
  103. {
  104. logger.warn("Could not load properties from " + location + ": " + ex.getMessage());
  105. }
  106. }
  107. else
  108. {
  109. throw ex;
  110. }
  111. }
  112. finally
  113. {
  114. if (is != null)
  115. {
  116. is.close();
  117. }
  118. }
  119. }
  120. }
  121. }
  122. }

其中propertiesPersister变量用我们写的DefaultPropertiesPersister类来实现,DecryptPropertiesPersister.java对象

[java] view
plain
 copy

  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.Reader;
  4. import java.util.Properties;
  5. import org.springframework.util.DefaultPropertiesPersister;
  6. import org.springframework.util.StringUtils;
  7. import com.huawei.smc.commons.constants.CommonContants;
  8. import com.huawei.smc.commons.constants.NumberConstants;
  9. import com.huawei.smc.commons.util.ThreeDesUtil;
  10. /**
  11. * 重载DefaultPropertiesPersister类
  12. *
  13. * @author  hKF44803
  14. * @version  [版本号, 2011-12-6]
  15. * @see  [相关类/方法]
  16. * @since  [产品/模块版本]
  17. */
  18. public class DecryptPropertiesPersister extends DefaultPropertiesPersister
  19. {
  20. // 加密后的字符串
  21. private String encryptContent;
  22. public String getEncryptContent()
  23. {
  24. return encryptContent;
  25. }
  26. /**
  27. * {@inheritDoc}
  28. */
  29. @Override
  30. protected void doLoad(Properties props, Reader reader)
  31. throws IOException
  32. {
  33. BufferedReader in = new BufferedReader(reader);
  34. // 最后写入的内容
  35. StringBuilder sbContent = new StringBuilder();
  36. // 循环读取文件
  37. while (true)
  38. {
  39. // 读取每一行
  40. String line = in.readLine();
  41. // 非空检查
  42. if (line == null)
  43. {
  44. break;
  45. }
  46. // 去掉空格
  47. line = StringUtils.trimLeadingWhitespace(line);
  48. // 读取行为空,跳出循环
  49. if (line.length() == 0)
  50. {
  51. // 长度为0,换行
  52. sbContent.append("\n");
  53. continue;
  54. }
  55. // 每行的第一个字符
  56. char firstChar = line.charAt(0);
  57. // 第一个字符不是#和!
  58. if (firstChar != '#' && firstChar != '!')
  59. {
  60. while (endsWithContinuationMarker(line))
  61. {
  62. String nextLine = in.readLine();
  63. line = line.substring(0, line.length() - 1);
  64. // 非空检查
  65. if (nextLine != null)
  66. {
  67. line += StringUtils.trimLeadingWhitespace(nextLine);
  68. }
  69. }
  70. // 查找等号所有位置的索引
  71. int separatorIndex = line.indexOf("=");
  72. // 没有等号
  73. if (separatorIndex == -1)
  74. {
  75. separatorIndex = line.indexOf(":");
  76. }
  77. // 取KEY
  78. String key = (separatorIndex != -1) ? line.substring(0, separatorIndex) : line;
  79. // 取KEY的值
  80. String value = (separatorIndex != -1) ? line.substring(separatorIndex + 1) : "";
  81. // 去掉空格
  82. key = StringUtils.trimTrailingWhitespace(key);
  83. value = StringUtils.trimLeadingWhitespace(value);
  84. // 将所有的属性放到持久的属性集*
  85. props.put(unescape(key), unescape(value));
  86. // DB属性文件
  87. if (CommonContants.DB_PASSWORD_PROPS.equals(key))
  88. {
  89. // 实例加密工具类
  90. ThreeDesUtil desUtil = new ThreeDesUtil();
  91. // DB密码解密
  92. if (value.startsWith(CommonContants.DECRYPT_FLAG))
  93. {
  94. // 去掉标识
  95. value = value.substring(NumberConstants.INT_5);
  96. // 对加密的属性进行3DES解密
  97. value = desUtil.decrypt(value);
  98. // 解密的值放到props中
  99. props.put(unescape(key), unescape(value));
  100. }
  101. // DB密码加密
  102. else
  103. {
  104. // 加密指定的值
  105. String strEncrypt = desUtil.encrypt(value);
  106. // 加密后的值添加一个标识,区分解密、加密
  107. value = CommonContants.DECRYPT_FLAG + strEncrypt;
  108. // 加密后的行
  109. line = key + CommonContants.PROPERTIES_SEPERATE + value;
  110. sbContent.append(line + "\n");
  111. }
  112. }
  113. // 追加其它的属性
  114. else
  115. {
  116. sbContent.append(line + "\n");
  117. }
  118. }
  119. else
  120. {
  121. // 追加读取的注释内容
  122. sbContent.append(line + "\n");
  123. }
  124. }
  125. encryptContent = sbContent.toString();
  126. }
  127. }

最后需要修改下applicationContext.xml文件,如下:

[java] view
plain
 copy

  1. <bean id="propertyConfigurer1" class="com.huawei.smc.commons.DecryptPropertyPlaceholderConfigurer">
  2. <property name="locations">
  3. <value>WEB-INF/classes/db.properties</value>
  4. </property>
  5. </bean>
  6. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
  7. <property name="driverClass" value="${db.driver}" />
  8. <property name="jdbcUrl" value="${db.url}" />
  9. <property name="user" value="${db.username}" />
  10. <property name="password" value="${db.password}" />
  11. <property name="checkoutTimeout" value="3000" />
  12. </bean>

这样对属性的加密就完成了,Spring进行加载的完成后,属性就加密了



提示:如果在配置中有多个配置文件需要加载,并且这些属性文件不需要做任何处理,那就需要添加下面的配置:

[java] view
plain
 copy

  1. <bean id="propertyConfigurer"
  2. class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  3. <property name="order" value="1" />
  4. <property name="ignoreUnresolvablePlaceholders" value="true" />
  5. <property name="locations">
  6. <value>WEB-INF/classes/smc.properties</value>
  7. </property>

Spring对外部属性文件指定的某个属性进行加密、解密的更多相关文章

  1. Java - 得到项目中properties属性文件中定义的属性值

    public static String getPropertiesValue(String fileName, String key) {   return ResourceBundle.getBu ...

  2. Java属性中指定Json的属性名称

    只需要使用注解"@JsonProperty(value = "pwd")" import com.fasterxml.jackson.annotation.Js ...

  3. 属性文件——Java&Spring

    属性文件 什么是属性文件 ? 定义:一个扩展名为properties文件,属性文件都是以key-value(键值对)来保存文件的内容,如:log4j.properties,db.properties等 ...

  4. 十八 Spring的JDBC模板:引入外部属性文件

    配置外部属性文件 配置文件里引入属性文件,两种方式 第一种: 第二种: 引入属性文件的值: 测试: <?xml version="1.0" encoding="UT ...

  5. java解析属性文件

    -----------------------解析属性文件----------------------------- /**   * 获取src下属性文件   * @param params   * ...

  6. Java操作属性文件,支持新增或更新多个属性

    Java操作属性文件.支持新增或更新多个属性 一.更新或新增单个属性的方法 /** * 写入properties信息 * @param filePath 绝对路径(包含文件名称和后缀名) * @par ...

  7. java:Properties属性文件概念

    java:Properties属性文件概念 在java之前的国际化程序中提出了一个属性文件的概念,属性文件的后缀是:*.properties,那么在java中提供了意个属性文件的专门操作类,Prope ...

  8. Java AES加密解密工具 -- GUI 、在线传输文件

    原理 对于任意长度的明文,AES首先对其进行分组,每组的长度为128位.分组之后将分别对每个128位的明文分组进行加密. 对于每个128位长度的明文分组的加密过程如下:     (1)将128位AES ...

  9. [原创]java WEB学习笔记99:Spring学习---Spring Bean配置:自动装配,配置bean之间的关系(继承/依赖),bean的作用域(singleton,prototype,web环境作用域),使用外部属性文件

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

随机推荐

  1. WebDriverWait等设置等待时间和超时时间

    1.显示等待 等待页面加载完成,找到某个条件发生后再继续执行后续代码,如果超过设置时间检测不到则抛出异常 WebDriverWait(driver, timeout, poll_frequency=0 ...

  2. rpmbuild spec 打包jar变小了、设置禁止压缩二进制文件Disable Binary stripping in rpmbuild

    Disable Binary stripping in rpmbuild 摘自:http://livecipher.blogspot.com/2012/06/disable-binary-stripp ...

  3. Mr_matcher的细节2

    1.参数服务器 ROS参数服务器能保存数据类型包括:strings, integers, floats, booleans, lists, dictionaries, iso8601 dates, a ...

  4. 在slam_gmapping中使用Log数据创建地图

    本文介绍使用机器人记录的tf变换和激光扫描数据来建立2D地图.并在ROS的图形化模拟环境rviz中通过重新回放记录的数据作为机器人真实传感器采集的输入,来观测地图动态创建过程. 1.ROS gmapp ...

  5. 运行monitor提示需要安装旧JAVA SE 6运行环境

    MAC系统下运行monitor命令 ➜ tools git:(master) ✗ monitor 提示如下: 若要打开Eclipse.app,您需要Java SE 6 runtime,您想现在安装一个 ...

  6. Monkey测试异常信息解读

    查看包名 1.cmd 下面输入 adb locat > D:\test.txt 2.ctrl+c 停掉刚刚 1 运行的进程 3.打开test.txt文件--搜索  Displayed  对应的内 ...

  7. PrintDocument or PrintPreviewDialog 打印

    /// <summary> /// /// </summary> /// <param name="sender"></param> ...

  8. 求整数数组(长度为n),出现大于2/n次数的数字

    条件:时间复杂度是O(n),空间复杂度是O(1) 方法1:标记法 , , , , , , , , , , , , , }; int len = arr.Length; int[] c = new in ...

  9. Mongo Windows 基本使用入门

    1.安装https://www.mongodb.com/download-center#community注意:安装 "install mongoDB compass" 不勾选下载 ...

  10. EF 配置实现建表与迁移

    通过EF 作为操作数据库的工具有一段时间了,也做了几个相对不大的项目,慢慢的也对EF的使用摸索出来了一些规则,虽然说不是技术难点,但是,我说的是但是,能够提高我们开发效率的棉花糖有时我们还是必须要吃的 ...