ソースを参照

Merge branch 'master' into jfinal-java8

James 8 年 前
コミット
ab284106e6

+ 6 - 1
src/main/java/com/jfinal/kit/Prop.java

@@ -55,7 +55,7 @@ public class Prop {
 	public Prop(String fileName, String encoding) {
 		InputStream inputStream = null;
 		try {
-			inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);		// properties.load(Prop.class.getResourceAsStream(fileName));
+			inputStream = getClassLoader().getResourceAsStream(fileName);		// properties.load(Prop.class.getResourceAsStream(fileName));
 			if (inputStream == null) {
 				throw new IllegalArgumentException("Properties file not found in classpath: " + fileName);
 			}
@@ -69,6 +69,11 @@ public class Prop {
 		}
 	}
 	
+	private ClassLoader getClassLoader() {
+		ClassLoader ret = Thread.currentThread().getContextClassLoader();
+		return ret != null ? ret : getClass().getClassLoader();
+	}
+	
 	/**
 	 * Prop constructor.
 	 * @see #Prop(File, String)

+ 4 - 0
src/main/java/com/jfinal/template/Engine.java

@@ -375,6 +375,10 @@ public class Engine {
 		return config;
 	}
 	
+	/**
+	 * 设置 true 为开发模式,支持模板文件热加载
+	 * 设置 false 为生产模式,不支持模板文件热加载,以达到更高的性能
+	 */
 	public Engine setDevMode(boolean devMode) {
 		this.devMode = devMode;
 		this.config.setDevMode(devMode);

+ 3 - 2
src/main/java/com/jfinal/template/EngineConfig.java

@@ -77,8 +77,9 @@ public class EngineConfig {
 	 * Add shared function with file
 	 */
 	public void addSharedFunction(String fileName) {
-		FileSource fileSource = new FileSource(baseTemplatePath, fileName, encoding);
-		doAddSharedFunction(fileSource, fileName);
+		// FileSource fileSource = new FileSource(baseTemplatePath, fileName, encoding);
+		ISource source = sourceFactory.getSource(baseTemplatePath, fileName, encoding);
+		doAddSharedFunction(source, fileName);
 	}
 	
 	private synchronized void doAddSharedFunction(ISource source, String fileName) {

+ 2 - 2
src/main/java/com/jfinal/template/ext/spring/JFinalViewResolver.java

@@ -78,10 +78,10 @@ public class JFinalViewResolver extends AbstractTemplateViewResolver {
 	
 	public JFinalViewResolver() {
 		setViewClass(requiredViewClass());
-		// setOrder(0);
+		setOrder(0);
+		setContentType("text/html;charset=UTF-8");
 		// setPrefix("/view/");
 		// setSuffix(".html");
-        // setContentType("text/html;charset=UTF-8");
 	}
 	
 	@Override

+ 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);
+	}
+}
+
+
+

+ 1 - 2
src/main/java/com/jfinal/template/source/FileSource.java

@@ -21,11 +21,10 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
-
 import com.jfinal.template.EngineConfig;
 
 /**
- * FileSource
+ * FileSource 用于从普通文件中加载模板内容
  */
 public class FileSource implements ISource {
 	

+ 3 - 3
src/main/java/com/jfinal/template/source/FileSourceFactory.java

@@ -17,9 +17,10 @@
 package com.jfinal.template.source;
 
 /**
- * FileSourceFactory 从指定的目录中加载模板文件
+ * FileSourceFactory 用于配置 Engine 使用 FileSource 加载模板文件
  * 
- * FileSourceFactory 为模板引擎默认配置,无需进行配置
+ * 注意:
+ *    FileSourceFactory 为模板引擎默认配置
  */
 public class FileSourceFactory implements ISourceFactory {
 	
@@ -31,4 +32,3 @@ public class FileSourceFactory implements ISourceFactory {
 
 
 
-

+ 1 - 1
src/main/java/com/jfinal/template/source/ISource.java

@@ -17,7 +17,7 @@
 package com.jfinal.template.source;
 
 /**
- * ISource
+ * ISource 用于表示模板内容的来源
  */
 public interface ISource {
 	

+ 2 - 2
src/main/java/com/jfinal/template/source/ISourceFactory.java

@@ -19,8 +19,8 @@ package com.jfinal.template.source;
 /**
  * ISourceFactory 用于为 engine 切换不同的 ISource 实现类
  * 
- * FileSourceFactory 从指定的目录中加载模板文件
- * ClassPathSourceFactory 从 class path 以及 jar 文件中加载模板文件
+ * FileSourceFactory 用于从指定的目录中加载模板文件
+ * ClassPathSourceFactory 用于从 class path 以及 jar 文件中加载模板文件
  * 
  * 配置示例:
  * engine.setSourceFactory(new ClassPathSourceFactory());

+ 1 - 1
src/main/java/com/jfinal/template/source/StringSource.java

@@ -21,7 +21,7 @@ import com.jfinal.kit.StrKit;
 import com.jfinal.template.EngineConfig;
 
 /**
- * StringSource
+ * StringSource 用于从 String 变量中加载模板内容
  */
 public class StringSource implements ISource {