Browse Source

支持从 class path 以及 jar 包之中加载模板文件

James 8 years ago
parent
commit
0d52991be3

+ 199 - 0
src/main/java/com/jfinal/template/source/ClassPathSource.java

@@ -0,0 +1,199 @@
+/**
+ * Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.template.source;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import com.jfinal.template.EngineConfig;
+
+/**
+ * ClassPathSource 用于从 class path 以及 jar 包之中加载模板内容
+ * 
+ * 注意:
+ * 1:如果被加载的文件是 class path 中的普通文件,则该文件支持热加载
+ * 2:如果被加载的文件处于 jar 包之中,则该文件不支持热加载
+ * 3:JFinal Template Engine 开启热加载需要配置 engine.setDevMode(true)
+ */
+public class ClassPathSource implements ISource {
+	
+	private String finalFileName;
+	private String fileName;
+	private String encoding;
+	
+	private boolean isInJar;
+	private long lastModified;
+	private ClassLoader classLoader;
+	private URL url;
+	
+	public ClassPathSource(String fileName) {
+		this(null, fileName, EngineConfig.DEFAULT_ENCODING);
+	}
+	
+	public ClassPathSource(String baseTemplatePath, String fileName) {
+		this(baseTemplatePath, fileName, EngineConfig.DEFAULT_ENCODING);
+	}
+	
+	public ClassPathSource(String baseTemplatePath, String fileName, String encoding) {
+		this.finalFileName = buildFinalFileName(baseTemplatePath, fileName);
+		this.fileName = fileName;
+		this.encoding= encoding;
+		this.classLoader = getClassLoader();
+		this.url = classLoader.getResource(finalFileName);
+		if (url == null) {
+			throw new IllegalArgumentException("File not found : \"" + finalFileName + "\"");
+		}
+		
+		processIsInJarAndLastModified();
+	}
+	
+	private void processIsInJarAndLastModified() {
+		try {
+			URLConnection conn = url.openConnection();
+			if ("jar".equals(url.getProtocol()) || conn instanceof JarURLConnection) {
+				isInJar = true;
+				lastModified = -1;
+			} else {
+				isInJar = false;
+				lastModified = conn.getLastModified();
+			}
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		}
+	}
+	
+	private ClassLoader getClassLoader() {
+		ClassLoader ret = Thread.currentThread().getContextClassLoader();
+		return ret != null ? ret : getClass().getClassLoader();
+	}
+	
+	private String buildFinalFileName(String baseTemplatePath, String fileName) {
+		String finalFileName;
+		if (baseTemplatePath != null) {
+			char firstChar = fileName.charAt(0);
+			if (firstChar == '/' || firstChar == '\\') {
+				finalFileName = baseTemplatePath + fileName;
+			} else {
+				finalFileName = baseTemplatePath + "/" + fileName;
+			}
+		} else {
+			finalFileName = fileName;
+		}
+		
+		if (finalFileName.charAt(0) == '/') {
+			finalFileName = finalFileName.substring(1);
+		}
+		
+		return finalFileName;
+	}
+	
+	public String getKey() {
+		return fileName;
+	}
+	
+	public String getEncoding() {
+		return encoding;
+	}
+	
+	private long getLastModified() {
+		try {
+			URLConnection conn = url.openConnection();
+			return conn.getLastModified();
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		}
+	}
+	
+	/**
+	 * 模板文件在 jar 包文件之内则不支持热加载
+	 */
+	public boolean isModified() {
+		return isInJar ? false : lastModified != getLastModified();
+	}
+	
+	public StringBuilder getContent() {
+		// 如果模板文件不在 jar 包文件之中,则需要更新 lastModified 值,否则在模板文件被修改后会不断 reload 模板文件
+		if (!isInJar) {
+			lastModified = getLastModified();
+		}
+		
+		InputStream inputStream = classLoader.getResourceAsStream(finalFileName);
+		if (inputStream == null) {
+			throw new RuntimeException("File not found : \"" + finalFileName + "\"");
+		}
+		
+		return loadFile(inputStream, encoding);
+	}
+	
+	public static StringBuilder loadFile(InputStream inputStream, String encoding) {
+		StringBuilder ret = new StringBuilder();
+		BufferedReader br = null;
+		try {
+			br = new BufferedReader(new InputStreamReader(inputStream, encoding));
+			// br = new BufferedReader(new FileReader(fileName));
+			String line = br.readLine();
+			if (line != null) {
+				ret.append(line);
+			} else {
+				return ret;
+			}
+			
+			while ((line=br.readLine()) != null) {
+				ret.append('\n').append(line);
+			}
+			return ret;
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+		finally {
+			if (br != null) {
+				try {
+					br.close();
+				} catch (IOException e) {
+					com.jfinal.kit.LogKit.error(e.getMessage(), e);
+				}
+			}
+		}
+	}
+	
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		sb.append("In Jar File: ").append(isInJar).append("\n");
+		sb.append("File name: ").append(fileName).append("\n");
+		sb.append("Final file name: ").append(finalFileName).append("\n");
+		sb.append("Last modified: ").append(lastModified).append("\n");
+		return sb.toString();
+	}
+}
+
+
+/*
+	protected File getFile(URL url) {
+		try {
+			// return new File(url.toURI().getSchemeSpecificPart());
+			return new File(url.toURI());
+		} catch (URISyntaxException ex) {
+			// Fallback for URLs that are not valid URIs (should hardly ever happen).
+			return new File(url.getFile());
+		}
+	}
+*/
+

+ 34 - 0
src/main/java/com/jfinal/template/source/ClassPathSourceFactory.java

@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.template.source;
+
+/**
+ * ClassPathSourceFactory 用于配置 Engine 使用 ClassPathSource 加载模板文件
+ * 
+ * 配置示例:
+ *    engine.baseTemplatePath(null);	// 清掉 base path
+ *    engine.setSourceFactory(new ClassPathSourceFactory());
+ */
+public class ClassPathSourceFactory implements ISourceFactory {
+	
+	public ISource getSource(String baseTemplatePath, String fileName, String encoding) {
+		return new ClassPathSource(baseTemplatePath, fileName, encoding);
+	}
+}
+
+
+