基于jpype1实现。
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -174,3 +174,4 @@ cython_debug/
|
|||||||
# PyPI configuration file
|
# PyPI configuration file
|
||||||
.pypirc
|
.pypirc
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|||||||
41
README.md
41
README.md
@@ -1,3 +1,42 @@
|
|||||||
# py-enjoy
|
# py-enjoy
|
||||||
|
|
||||||
jfinal-enjoy 5.2.2 的python 3.9.0 实现,基于jpype1实现。 mrzhou@miw.cn
|
jfinal-enjoy 5.2.2 的python 3.9.0 实现,基于jpype1实现。
|
||||||
|
python port by mrzhou@miw.cn
|
||||||
|
|
||||||
|
### 使用样例
|
||||||
|
```
|
||||||
|
# 1. 配置参数(必须修改为你的实际路径)
|
||||||
|
JAR_PATH = "enjoy-5.2.2.jar" # enjoy-5.2.2.jar的绝对/相对路径
|
||||||
|
TEMPLATE_BASE_PATH = "./templates" # 模板文件所在目录(如index.html放在这个目录下)
|
||||||
|
|
||||||
|
# 2. 创建Enjoy实例(初始化Engine)
|
||||||
|
try:
|
||||||
|
enjoy = Enjoy(
|
||||||
|
jar_path=JAR_PATH,
|
||||||
|
template_base_path=TEMPLATE_BASE_PATH
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. 准备模板参数
|
||||||
|
render_data = {
|
||||||
|
"name": "JFinal Enjoy 5.2.2测试",
|
||||||
|
"hobbies": ["Python调用Java", "模板渲染", "跨语言开发"],
|
||||||
|
"user": {"age": 25, "gender": "男"}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 4. 渲染模板(tempStr是模板文件名,相对于TEMPLATE_BASE_PATH)
|
||||||
|
result = enjoy.render(
|
||||||
|
tempStr="index.html", # 模板文件:./templates/index.html
|
||||||
|
data=render_data # 渲染数据(Python字典)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 5. 输出结果
|
||||||
|
print("\n=== 模板渲染结果 ===")
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
except RuntimeError as e:
|
||||||
|
print(f"\n执行失败: {e}")
|
||||||
|
finally:
|
||||||
|
# 6. 关闭资源
|
||||||
|
if 'enjoy' in locals():
|
||||||
|
enjoy.close()
|
||||||
|
```
|
||||||
BIN
enjoy-5.2.2.jar
Normal file
BIN
enjoy-5.2.2.jar
Normal file
Binary file not shown.
159
enjoy.py
Normal file
159
enjoy.py
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import jpype
|
||||||
|
import os
|
||||||
|
from typing import Dict, Any, Optional
|
||||||
|
|
||||||
|
class Enjoy:
|
||||||
|
"""
|
||||||
|
适配JFinal Enjoy 5.2.2模板引擎的Python调用类
|
||||||
|
核心类:com.jfinal.template.Engine
|
||||||
|
实现:mrzhou@miw.cn
|
||||||
|
"""
|
||||||
|
_instance: Optional['Enjoy'] = None
|
||||||
|
_jvm_started: bool = False
|
||||||
|
_engine: Optional[Any] = None # 保存JFinal Engine实例
|
||||||
|
|
||||||
|
def __new__(cls, jar_path: str, template_base_path: str = "./"):
|
||||||
|
"""单例模式:全局唯一Engine实例"""
|
||||||
|
if cls._instance is None:
|
||||||
|
cls._instance = super().__new__(cls)
|
||||||
|
cls._instance.jar_path = os.path.abspath(jar_path)
|
||||||
|
cls._instance.template_base_path = os.path.abspath(template_base_path)
|
||||||
|
cls._instance._init_jvm()
|
||||||
|
cls._instance._init_engine() # 初始化JFinal Engine
|
||||||
|
return cls._instance
|
||||||
|
|
||||||
|
def _init_jvm(self):
|
||||||
|
"""启动JVM并加载enjoy-5.2.2.jar"""
|
||||||
|
if not self._jvm_started:
|
||||||
|
try:
|
||||||
|
jvm_path = jpype.getDefaultJVMPath()
|
||||||
|
# 修复:所有位置参数在前,关键字参数在后
|
||||||
|
jpype.startJVM(
|
||||||
|
jvm_path, # 位置参数1
|
||||||
|
"-ea", # 位置参数2
|
||||||
|
f"-Djava.class.path={self.jar_path}", # 位置参数3
|
||||||
|
"-Dfile.encoding=UTF-8", # 位置参数4(移到关键字参数前)
|
||||||
|
convertStrings=False # 关键字参数(必须在最后)
|
||||||
|
)
|
||||||
|
self._jvm_started = True
|
||||||
|
print(f"JVM启动成功 | 工作目录: {jpype.java.lang.System.getProperty('user.dir')}")
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"JVM启动失败: {e}") from e
|
||||||
|
|
||||||
|
def _init_engine(self):
|
||||||
|
"""初始化JFinal Engine实例(核心)"""
|
||||||
|
try:
|
||||||
|
# 加载JFinal Engine类
|
||||||
|
Engine = jpype.JClass("com.jfinal.template.Engine")
|
||||||
|
# 获取默认Engine实例(JFinal推荐单例使用)
|
||||||
|
self._engine = Engine.use()
|
||||||
|
# 配置模板基础路径(关键:指定模板文件所在目录)
|
||||||
|
self._engine.setBaseTemplatePath(self.template_base_path)
|
||||||
|
# 可选配置:设置编码、开启热加载等
|
||||||
|
self._engine.setEncoding("UTF-8")
|
||||||
|
self._engine.setDevMode(True) # 开发模式,便于调试
|
||||||
|
print(f"Engine初始化成功 | 模板基础路径: {self.template_base_path}")
|
||||||
|
except jpype.JException as e:
|
||||||
|
e.printStackTrace()
|
||||||
|
raise RuntimeError(f"Engine初始化失败: {e.getMessage()}") from e
|
||||||
|
|
||||||
|
def _convert_python_to_java(self, obj: Any) -> Any:
|
||||||
|
"""转换Python数据为Java Map(适配Enjoy模板数据格式)"""
|
||||||
|
if isinstance(obj, dict):
|
||||||
|
# 优先使用JFinal的Map(也可用java.util.HashMap)
|
||||||
|
HashMap = jpype.JClass("java.util.HashMap")
|
||||||
|
java_map = HashMap()
|
||||||
|
for key, value in obj.items():
|
||||||
|
# 递归转换嵌套数据
|
||||||
|
if isinstance(value, (dict, list)):
|
||||||
|
java_map.put(key, self._convert_python_to_java(value))
|
||||||
|
else:
|
||||||
|
java_map.put(key, value)
|
||||||
|
return java_map
|
||||||
|
elif isinstance(obj, list):
|
||||||
|
return jpype.JArray(jpype.JObject)([self._convert_python_to_java(x) for x in obj])
|
||||||
|
else:
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def render(self, tempStr: str, data: Dict[str, Any]) -> str:
|
||||||
|
"""
|
||||||
|
渲染Enjoy模板(核心方法)
|
||||||
|
:param tempStr: 模板文件名(相对于baseTemplatePath的路径,如index.html)
|
||||||
|
:param data: 模板渲染数据(Python字典)
|
||||||
|
:return: 渲染后的字符串
|
||||||
|
"""
|
||||||
|
if not self._engine:
|
||||||
|
raise RuntimeError("Engine未初始化,请检查Jar包路径")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 1. 转换Python字典为Java Map
|
||||||
|
java_data = self._convert_python_to_java(data)
|
||||||
|
# 2. 获取Template实例(Engine.getTemplate)
|
||||||
|
template = self._engine.getTemplate(tempStr)
|
||||||
|
# 3. 渲染模板:使用Writer接收结果
|
||||||
|
StringWriter = jpype.JClass("java.io.StringWriter")
|
||||||
|
writer = StringWriter()
|
||||||
|
template.render(java_data, writer)
|
||||||
|
# 4. 转换为Python字符串
|
||||||
|
result = writer.toString()
|
||||||
|
writer.close()
|
||||||
|
return result
|
||||||
|
|
||||||
|
except jpype.JException as e:
|
||||||
|
print("\n=== JFinal Enjoy异常详情 ===")
|
||||||
|
e.printStackTrace()
|
||||||
|
raise RuntimeError(f"模板渲染失败: {e.getMessage()}") from e
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"调用失败: {e}") from e
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""关闭JVM,释放资源"""
|
||||||
|
if self._jvm_started:
|
||||||
|
jpype.shutdownJVM()
|
||||||
|
self._jvm_started = False
|
||||||
|
self._engine = None
|
||||||
|
self.__class__._instance = None
|
||||||
|
print("JVM已关闭")
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
"""析构函数:自动关闭"""
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# 标准调用示例(适配enjoy-5.2.2.jar)
|
||||||
|
# ------------------------------
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# 1. 配置参数(必须修改为你的实际路径)
|
||||||
|
JAR_PATH = "enjoy-5.2.2.jar" # enjoy-5.2.2.jar的绝对/相对路径
|
||||||
|
TEMPLATE_BASE_PATH = "./templates" # 模板文件所在目录(如index.html放在这个目录下)
|
||||||
|
|
||||||
|
# 2. 创建Enjoy实例(初始化Engine)
|
||||||
|
try:
|
||||||
|
enjoy = Enjoy(
|
||||||
|
jar_path=JAR_PATH,
|
||||||
|
template_base_path=TEMPLATE_BASE_PATH
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. 准备模板参数
|
||||||
|
render_data = {
|
||||||
|
"name": "JFinal Enjoy 5.2.2测试",
|
||||||
|
"hobbies": ["Python调用Java", "模板渲染", "跨语言开发"],
|
||||||
|
"user": {"age": 25, "gender": "男"}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 4. 渲染模板(tempStr是模板文件名,相对于TEMPLATE_BASE_PATH)
|
||||||
|
result = enjoy.render(
|
||||||
|
tempStr="index.html", # 模板文件:./templates/index.html
|
||||||
|
data=render_data # 渲染数据(Python字典)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 5. 输出结果
|
||||||
|
print("\n=== 模板渲染结果 ===")
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
except RuntimeError as e:
|
||||||
|
print(f"\n执行失败: {e}")
|
||||||
|
finally:
|
||||||
|
# 6. 关闭资源
|
||||||
|
if 'enjoy' in locals():
|
||||||
|
enjoy.close()
|
||||||
29
templates/index.html
Normal file
29
templates/index.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
#(name)
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
#for(i : hobbies)
|
||||||
|
#(i)
|
||||||
|
#end
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
#for(i : scores)
|
||||||
|
#(i)
|
||||||
|
#end
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
#for(i : user)
|
||||||
|
#(i.key) #(i.value)
|
||||||
|
#end
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user