diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index c6a93ca..629aada 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,14 +5,9 @@
-
-
-
+
-
-
-
@@ -94,11 +89,11 @@
+
-
@@ -171,7 +166,7 @@
-
+
1695868954392
@@ -224,7 +219,15 @@
1788925494296
-
+
+
+ 1789027539831
+
+
+
+ 1789027539831
+
+
diff --git a/src/main/java/io/v/nutz/web/commons/ext/beetl/BeetlCustomResourceLoader.java b/src/main/java/io/v/nutz/web/commons/ext/beetl/BeetlCustomResourceLoader.java
new file mode 100644
index 0000000..0a432e0
--- /dev/null
+++ b/src/main/java/io/v/nutz/web/commons/ext/beetl/BeetlCustomResourceLoader.java
@@ -0,0 +1,80 @@
+package io.v.nutz.web.commons.ext.beetl;
+
+import org.beetl.core.Resource;
+import org.beetl.core.misc.BeetlUtil;
+import org.beetl.core.resource.ClasspathResource;
+import org.beetl.core.resource.ClasspathResourceLoader;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class BeetlCustomResourceLoader extends ClasspathResourceLoader {
+
+ @Override
+ public Resource getResource(String key) {
+ Resource resource = new ClasspathResource(key, this.getChildPath(super.getRoot(), key), this);
+ return resource;
+ }
+
+ @Override
+ public String getResourceId(Resource resource, String id) {
+// return resource == null ? id : BeetlUtil.getRelPath(resource.getId(), id);
+ return getRelPath(resource.getId(), id);
+ }
+
+ /**
+ * 增加判断相对路径
+ * 光见鬼
+ */
+ private String getRelPath(String siblings, String resourceId) {
+ // 参数校验
+ if (resourceId == null || resourceId.isEmpty()) {
+ throw new RuntimeException("资源ID为空,参数错");
+ }
+
+ // 如果是绝对路径,直接返回(以 / 或 \ 开头)
+ if (resourceId.charAt(0) == '\\' || resourceId.charAt(0) == '/') {
+ if (BeetlUtil.isOutsideOfRoot(resourceId)) {
+ throw new RuntimeException("不能访问外部文件或者模板");
+ }
+ return resourceId;
+ }
+
+ // 处理相对路径
+ String baseDir = siblings;
+ // 如果siblings是文件路径,获取其所在目录
+ int lastSeparatorIndex = Math.max(siblings.lastIndexOf('/'), siblings.lastIndexOf('\\'));
+ if (lastSeparatorIndex > 0) {
+ baseDir = siblings.substring(0, lastSeparatorIndex + 1);
+ }
+
+ // 分割路径
+ String[] parts = resourceId.replace('\\', '/').split("/");
+ List baseParts = new ArrayList<>(
+ Arrays.asList(baseDir.replace('\\', '/').split("/"))
+ );
+ baseParts.removeIf(String::isEmpty);
+
+ // 处理 ../ 和 ./
+ for (String part : parts) {
+ if ("..".equals(part)) {
+ if (!baseParts.isEmpty()) {
+ baseParts.remove(baseParts.size() - 1);
+ }
+ } else if (!".".equals(part) && !part.isEmpty()) {
+ baseParts.add(part);
+ }
+ }
+
+ // 组合最终路径
+ String result = "/" + String.join("/", baseParts);
+
+ // 检查是否访问外部文件
+ if (BeetlUtil.isOutsideOfRoot(result)) {
+ throw new RuntimeException("不能访问外部文件或者模板");
+ }
+ return result;
+ }
+
+}