一种利用注释让Java支持多行字符串的方法

阅读更多
(2018.1.21注:本文已过时,又找到一种好一点的利用注释支持多行字符串的方法,见 https://my.oschina.net/drinkjava2/blog/1611028 )

从BeetlSql项目将SQL全放在Beetl模板里得到启发,又想到一个比较偏门的用法。以下代码实测通过,详见jSqlBox项目的test\examples\multipleLineSQL\SqlTemplateDemo.java源程序,此示例特殊点在于:运行时必须将此源程序拷贝一份在类根目录(或Maven管理的Resource目录下), 并将后缀".java"改为".sql"

public class SqlTemplateDemo extends TestBase {

	//@formatter:off	
	public static class InsertUser extends SqlTemplate {
		public InsertUser(Object name, Object address, Object age){ 
		/* insert into 
		   users 
		   (username, address, age) */ empty(name,address,age);
		/* values  (?,?,?)*/ 
		}
	}
	
	public static class FindUsers extends SqlTemplate  {
		public FindUsers(Object name, Object age){ 
		/* select count(*) 
		   from
		   users
		  where */
		/* username=? */empty(name); 
		/* and age>? */empty(age);
		/* order by username */  
		}
	}

    public static class GetUserCount extends SqlTemplate  {    
        /* select count(*) 
           from users  */    
    }   
    
	public static class SqlTemplateEndTag{}
	
	@Test
	public void doTest() { 
		Dao.executeInsert(new InsertUser("Tom","BeiJing",10).toString());
		Dao.executeInsert(new InsertUser("Sam","ShangHai",20).toString());
		Assert.assertEquals((Integer) 1,  Dao.queryForInteger(new FindUsers("Sam",15).toString()));
		Assert.assertEquals((Integer) 2,  Dao.queryForInteger(new GetUserCount().toString())); 
	} 	
}

以上代码是利用Java源程序作为模板文件来统一放置SQL,以便于DBA管理。其优点在于:

1)没有引入第三方模板,直接用Java作为模板文件
2)支持多行字符串, 且没有引入IDE插件或Maven编译插件等,通用性好。
3)支持Java方法和模板混用,模板负责存储SQL,Java负责赋值(利用ThreadLocal),互不干拢。
4)public static class的类名即为SQL ID,便于重命名重构和SQL的快速定位(Ctrl+鼠标左键即可),这是文本方式模板无法做到的,后者必须用文本搜索功能才能定位SQL。
缺点是:
1)每次模板更改后,还必须手工拷贝一份同样的文件放在类根目录作为资源文件
2)因为SQL写在注释中, 所以必须利用标记 //@formatter:off 来关闭IDE(我用Eclipse)的格式化功能,防止IDE误格式化。
3)从SQL管理角度出发,模板文件中要注意不要放入过多除SQL以外的无关代码。

以上方法主要应用于SQL模板,但是其它场合如需要用到Java支持多行字符串的,也可以借签。

注:2017.5.17再更新一下,以下是一个通用的支持多行字符串的基类,实现了在开发阶段从源码读取(TextSupport类或其子类在getJavaSrcFolder方法返回值中要给出源码目录),布署阶段从资源文件读取(布署时改一下getJavaSrcFolder方法使其返回空值并拷贝Java模板到类根目类,并改为.txt后缀):

package util;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;

/**
 * TextSupport is base class for Java text(multiple line Strings) template.
 */
public class TextSupport {

	public String getJavaSrcFolder() {
		return "F:/your_project_folder/src/test/java/";
	}

	@Override
	public String toString() {
		try {
			if (StringUtils.isEmpty(getJavaSrcFolder()))
				return extractTextFromComments(getTextFromResourceFile());
			else
				return extractTextFromComments(getTextFromJavaFile());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	private String extractTextFromComments(String templateText) {
		String thisPublicStaticClassName = this.getClass().getSimpleName();
		String classText = StringUtils.substringBetween(templateText,
				"public static class " + thisPublicStaticClassName, "*/}");
		if (StringUtils.isEmpty(classText))
			throw new RuntimeException("Can not find text between \"public static class " + thisPublicStaticClassName
					+ " and end tag \"*/}\"");
		StringBuilder sb = new StringBuilder();
		for (String str : StringUtils.substringsBetween(classText + "*/", "/*", "*/"))
			sb.append(str);
		return sb.toString();
	}

	private String getTextFromJavaFile() throws IOException {
		String className = this.getClass().getName(); // aaa.bbb.CCC$DDD
		String fileName = getJavaSrcFolder()
				+ StringUtils.replace(StringUtils.substringBeforeLast(className, "$"), ".", "/") + ".java";
		return FileUtils.readFileToString(new File(fileName));
	}

	private String getTextFromResourceFile() throws IOException {
		String className = StringUtils.substringAfterLast("." + this.getClass().getName(), ".");// CCC$DDD
		String resFile = StringUtils.substringBefore(className, "$") + ".txt";// CCC.txt
		URL url = this.getClass().getResource("/" + resFile);
		if (url == null)
			throw new RuntimeException("Can not find resource file \"" + resFile + "\"");
		return FileUtils.readFileToString(new File(url.getFile()));
	}

	public static void main(String[] args) {
		System.out.println("Text=" + new DemoString());
	}

	//@formatter:off
	public static class DemoString extends TextSupport{   
	 /*   
	  Hello,
	  This is multiple line strings demo
     */} 	
}


你可能感兴趣的:(Java,支持,多行字符串,多行文本,SQL)