Spring 项目中把大量的 SQL 分散在 Java 代码中,无 Here Doc 的情况下用加号来连接写着实在是不爽,于是之前思考这个 Spring 项目中把 SQL 语句写在 .sql 文件中 -- 把它们写在 *.sql 文件中,但是这个 *.sql 需要特定的格式来标识属性 Key
--!select.user
select id, firstname, lastname, address
--!update.user
update ........
而且还需要一个额外的类 SqlPropertySourceFactory 来解析上面的 *.sql 文件, 识别出 select.user 是 Key, 紧接着后面的块是相应的属性值,用注解引用它时还有点额外的 factory 属性来配置,如
@PropertySource(value = "classpath:sql/queries.sql", factory = SqlPropertySourceFactory.class)
所以一直在思考是否能够再简单些,是否能用一个自定义的注解,如
@SqlPropertySource("classpath:sql/queries.sql")
捉摸了很久,似乎有点难度,不过再不断发掘的过程中找到了这个类 org.springframework.core.io.support.PropertiesLoaderUtils
, 有下面的代码片断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public static Properties loadProperties(EncodedResource resource) throws IOException { Properties props = new Properties(); fillProperties(props, resource); return props; } ...... static void fillProperties(Properties props, EncodedResource resource, PropertiesPersister persister) throws IOException { InputStream stream = null; Reader reader = null; try { String filename = resource.getResource().getFilename(); if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) { stream = resource.getInputStream(); persister.loadFromXml(props, stream); } else if (resource.requiresReader()) { ...... |
也就是说其实我们是可以用 XML 文件来定义属性的。
继续深挖到 run.util.spi.XmlPropertiesProvider
, 这居然是来自于 rt.jar, 原来用 XML 定义属性由来已久。Spring 所用的一个实现同样是 rt.jar 中的 sun.util.xml.PlatformXmlPropertiesProvider
, 看到这个类的前几行我瞬间就豁然开朗了
1 2 3 |
private static final String PROPS_DTD_URI = "http://java.sun.com/dtd/properties.dtd"; private static final String PROPS_DTD = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!-- DTD for properties --><!ELEMENT properties ( comment?, entry* ) ><!ATTLIST properties version CDATA #FIXED \"1.0\"><!ELEMENT comment (#PCDATA) ><!ELEMENT entry (#PCDATA) ><!ATTLIST entry key CDATA #REQUIRED>"; private static final String EXTERNAL_XML_VERSION = "1.0"; |
定义属性的 XML 该如何写已经一目了然了,关键是 http://java.sun.com/dtd/properties.dtd 给我们的定义,也可以直接抓下它的定义来
➜ / curl -L http://java.sun.com/dtd/properties.dtd
<!--
Copyright 2006 Sun Microsystems, Inc. All rights reserved.
-->
<!-- DTD for properties -->
<!ELEMENT properties ( comment?, entry* ) >
<!ATTLIST properties version CDATA #FIXED "1.0">
<!ELEMENT comment (#PCDATA) >
<!ELEMENT entry (#PCDATA) >
<!ATTLIST entry key CDATA #REQUIRED>
根节点是 properties
, 其下是多个 entry
定义,entry 的 key 属性即属性的 Key, entry 中是 CDATA 文本内容就是属性值。下面是一个实际的属性 XML 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties PUBLIC "xml property dtd" "http://java.sun.com/dtd/properties.dtd"> <properties> <entry key="select.user"> select id, firstname, lastname, address from user where id = ? </entry> <entry key="update.user"> <![CDATA[ update user set address='<where>' where id = ? ]]> </entry> </properties> |
如果 entry 中有 XML 的特殊字符就用 <![CDATA[...]>
框起来,无 XML Entities 就无所谓了。
现在要引用定义在 XML 中的属性值就简单了,没有什么特别的,不需要额外的文件解析类,只是文件扩展名的不同而已。比如在你的 Spring 代码中使用如下注解
1 2 3 4 |
@PropertySource("sql/queries.sql.xml") //由于默认是 classpath 所以无需写成 @PropertySource("classpath:sql/queries.sql.xml") public class JavaConfig { ...... } |
如此,定义在 sql/queries.sql.xml
便进到属性环境中去了,在任何一个 Spring Bean 中可以用 @Value("${select.uer}")
引用到了
1 2 3 4 5 6 7 |
@Named public class UserRepository { @Value("${select.user}") private String selectUserSql; ........ |
从此再也不用那个 SqlPropertySourceFactory 了。
IDE 打开 queries.sql.xml 只会以 XML 文件格式来进行语法高亮,如果想要 IDE 对其中的 SQL 语法进行高亮显示,可以修改 IDE 的配置,让 SQL 文件类型也包含 *.sql.xml
这个模式的文件名,那么每次在 IDE 中打开后缀为 *.sql.xml
都会认成是 SQL 文件,更增添了可读性。
2019-06-12
Spring 对 xml 写属性文件的支持其实是由 JDK 的 Properties 类自 JDK 1.5 开始提供的,见 Properties 的 JavaDoc。Properties 中新增了 loadFromXML(Inputstream)
和 storeToXML(OutputStream, String, String)
, 来见识一下用 Properties 如何加载前方那个 sql/queries.sql.xml
配置的属性文件
1 2 3 |
Properties properties = new Properties(); properties.loadFromXML(Thread.currentThread().getContextClassLoader().getResourceAsStream("sql/queries.sql.xml")); System.out.println(properties.getProperty("")); |
输出
select id, firstname, lastname, address
from user
where id = ?
本文链接 https://yanbin.blog/spring-properties-sql-in-xml-file/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。