diff --git a/solon-jakarta-projects/solon-server/solon-server-tomcat-add-jsp-jakarta/pom.xml b/solon-jakarta-projects/solon-server/solon-server-tomcat-add-jsp-jakarta/pom.xml index 013d86a1ccb001aca8867825873542dbc8e2ed7d..1369ff417abcd621a9b45ca65d64a56704127eb6 100644 --- a/solon-jakarta-projects/solon-server/solon-server-tomcat-add-jsp-jakarta/pom.xml +++ b/solon-jakarta-projects/solon-server/solon-server-tomcat-add-jsp-jakarta/pom.xml @@ -16,6 +16,10 @@ jar + + org.noear + solon-server-tomcat-jakarta + jakarta.servlet jakarta.servlet-api diff --git a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/pom.xml b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/pom.xml index 51e8ef4372420706d22d07ad07c41fd9f81b699d..d9df215aba3fb07d1949b987e99748903eba4ab3 100644 --- a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/pom.xml +++ b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/pom.xml @@ -70,5 +70,10 @@ solon-logging-simple test + + org.noear + solon-view-jsp-jakarta + test + \ No newline at end of file diff --git a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/main/java/org/noear/solon/server/tomcat/TomcatServerJsp.java b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/main/java/org/noear/solon/server/tomcat/TomcatServerJsp.java index 98d9c8748ccec9261f51aad352fccca816420ee4..84cfc84df5a3b616714d8c955e0bb04c7e2ffe13 100644 --- a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/main/java/org/noear/solon/server/tomcat/TomcatServerJsp.java +++ b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/main/java/org/noear/solon/server/tomcat/TomcatServerJsp.java @@ -15,13 +15,27 @@ */ package org.noear.solon.server.tomcat; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import org.apache.catalina.Context; import org.apache.catalina.Wrapper; +import org.apache.catalina.startup.Tomcat; import org.apache.jasper.servlet.JasperInitializer; -import org.apache.jasper.servlet.JspServlet; +import org.noear.solon.Solon; +import org.noear.solon.Utils; +import org.noear.solon.core.runtime.NativeDetector; +import org.noear.solon.core.util.ResourceUtil; import org.noear.solon.server.prop.impl.HttpServerProps; +import org.noear.solon.server.tomcat.jsp.JspTldLocator; -import java.io.IOException; +import jakarta.servlet.descriptor.JspConfigDescriptor; +import jakarta.servlet.descriptor.TaglibDescriptor; /** * @author noear 2025/11/29 created @@ -34,28 +48,92 @@ public class TomcatServerJsp extends TomcatServer { @Override protected void initContext() throws IOException { Context ctx = getContext(); - + //jsp try { - addJspServlet(ctx); - - JasperInitializer jasperInstance = new JasperInitializer(); - ctx.addServletContainerInitializer(jasperInstance, null); + String resourcePath = getResourceRoot(); + if(Utils.isBlank(resourcePath)) { + resourcePath = getClass().getClassLoader().getResource("").getPath(); + } + ctx.setDocBase(resourcePath); + addJspSupport(ctx); + addTldSupport(ctx); } catch (Exception e) { log.debug(e.getMessage(), e); } } - private void addJspServlet(Context context) { - Wrapper jspServlet = context.createWrapper(); - jspServlet.setName("jsp"); - jspServlet.setServlet(new JspServlet()); + + private void addJspSupport(Context context) throws IOException { + // 注册JSP Servlet(Tomcat需要显式注册JspServlet) + Wrapper jspServlet = Tomcat.addServlet(context, "jsp", "org.apache.jasper.servlet.JspServlet"); jspServlet.addInitParameter("fork", "false"); jspServlet.addInitParameter("xpoweredBy", "false"); - jspServlet.setLoadOnStartup(3); - - context.addChild(jspServlet); +// jspServlet.addInitParameter("development", "true"); // 开发模式,便于调试 + + // 设置JSP文件映射 context.addServletMappingDecoded("*.jsp", "jsp"); context.addServletMappingDecoded("*.jspx", "jsp"); + + JasperInitializer jasperInstance = new JasperInitializer(); + context.addServletContainerInitializer(jasperInstance, null); + } + + private void addTldSupport(Context ctx) throws IOException { + // 扫描TLD文件并注册 + Map tagLibInfos = JspTldLocator.createTldInfos("WEB-INF", "templates"); + + if (tagLibInfos.size()>0) { + List taglibs = new ArrayList<>(tagLibInfos.values()); + JspConfigDescriptor jspConfigDescriptor = new org.apache.tomcat.util.descriptor.web.JspConfigDescriptorImpl( + new ArrayList<>(), taglibs); + ctx.setJspConfigDescriptor(jspConfigDescriptor); +// ctx.getServletContext().setAttribute("jakarta.servlet.context.tldScan", true); + } + } + + private String getResourceRoot() throws FileNotFoundException { + URL rootURL = getRootPath(); + if (rootURL == null) { + if (NativeDetector.inNativeImage()) { + return ""; + } + + throw new FileNotFoundException("Unable to find root"); + } + + String resURL = rootURL.toString(); + + if (Solon.cfg().isDebugMode() && (resURL.startsWith("jar:") == false)) { + int endIndex = resURL.indexOf("target"); + return resURL.substring(0, endIndex) + "src/main/resources/"; + } + + return ""; + } + + private URL getRootPath() { + URL root = ResourceUtil.getResource("/"); + if (root != null) { + return root; + } + try { + URL temp = ResourceUtil.getResource(""); + if (temp == null) { + return null; + } + + String path = temp.toString(); + if (path.startsWith("jar:")) { + int endIndex = path.indexOf("!"); + path = path.substring(0, endIndex + 1) + "/"; + } else { + return null; + } + return new URL(path); + } catch (MalformedURLException e) { + return null; + } } + } \ No newline at end of file diff --git a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/main/java/org/noear/solon/server/tomcat/jsp/JspTldLocator.java b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/main/java/org/noear/solon/server/tomcat/jsp/JspTldLocator.java new file mode 100644 index 0000000000000000000000000000000000000000..44648852b65fe17bd2f1d0aa58c99af0a22980b2 --- /dev/null +++ b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/main/java/org/noear/solon/server/tomcat/jsp/JspTldLocator.java @@ -0,0 +1,91 @@ +/* + * Copyright 2017-2025 noear.org and authors + * + * 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 + * + * https://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 org.noear.solon.server.tomcat.jsp; + +import org.apache.tomcat.util.descriptor.tld.TaglibXml; +import org.apache.tomcat.util.descriptor.tld.TldParser; +import org.apache.tomcat.util.descriptor.tld.TldResourcePath; +import org.noear.solon.Utils; +import org.noear.solon.core.AppClassLoader; +import org.noear.solon.core.util.ResourceUtil; +import org.noear.solon.core.util.ScanUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.servlet.descriptor.TaglibDescriptor; + +import java.io.IOException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * TLD文件定位器 + */ +public class JspTldLocator { + private static final Logger log = LoggerFactory.getLogger(JspTldLocator.class); + + private JspTldLocator() { + + } + public static Map createTldInfos(String... tldDirs) throws IOException { + Map tagLibInfos = new HashMap<>(); + + TldParser tldParser = new TldParser(true, true, true); + + for (String tldDir : tldDirs) { + // 扫描指定目录下的TLD文件 + Set urls = ScanUtil.scan(AppClassLoader.global(), tldDir, n -> n.endsWith(".tld")); + + if (Utils.isNotEmpty(urls)) { + for (String uri : urls) { + uri = "/" + uri; + + URL resUri = ResourceUtil.getResource(uri); + TldResourcePath tldResourcePath = new TldResourcePath(resUri, uri); + + try { + TaglibXml taglibXml = tldParser.parse(tldResourcePath); + + // 创建TLD描述符 + final String taglibUri = taglibXml.getUri(); + final String taglibLocation = uri; + + TaglibDescriptor descriptor = new TaglibDescriptor() { + @Override + public String getTaglibURI() { + return taglibUri; + } + + @Override + public String getTaglibLocation() { + return taglibLocation; + } + }; + + tagLibInfos.put(taglibUri, descriptor); + } catch (Exception e) { + log.warn("TLD failed to load, uri={}", uri, e); + } + } + } + } + + return tagLibInfos; + } + +} \ No newline at end of file diff --git a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/java/demo3013/controller/HelloworldController.java b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/java/demo3013/controller/HelloworldController.java index 20f5842abea492e4ffb75371237269fb2423e3f8..c0a3387cc8fe29438bde19bb0073c884ea7262fe 100644 --- a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/java/demo3013/controller/HelloworldController.java +++ b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/java/demo3013/controller/HelloworldController.java @@ -33,4 +33,25 @@ public class HelloworldController { return vm; } + + @Mapping("/hellotld") + public Object hellotld(Context ctx){ + UserModel m = new UserModel(); + m.setId(11); + m.setName("刘之西东2"); + m.setSex(2); + + ModelAndView vm = new ModelAndView("helloworld2.jsp"); + + vm.put("title","demo2"); + vm.put("message","hello world2!"); + + vm.put("m",m); + + vm.put("user", user); + + vm.put("ctx",ctx); + + return vm; + } } diff --git a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/resources/app.properties b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/resources/app.properties index a571472c888fdf9926754270bb3798be301af921..86a341a08ed77496740b48c6a7ef53fc2b70a4a3 100644 --- a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/resources/app.properties +++ b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/resources/app.properties @@ -9,4 +9,7 @@ solon.output.meta=1 custom.user=world -solon.view.mapping.vm: org.noear.solon.view.jsp.JspRender +#solon.view.mapping.vm: org.noear.solon.view.jsp.JspRender +solon.view.mapping.jsp=org.noear.solon.view.jsp.JspRender + +solon.view.prefix=/templates diff --git a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/resources/templates/helloworld.jsp b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/resources/templates/helloworld.jsp index 1793a6aa8bb1786ba2305b227b5b52fc92261bd9..25631047b52ee16751c3c0deab348c6662bc4bcd 100644 --- a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/resources/templates/helloworld.jsp +++ b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/resources/templates/helloworld.jsp @@ -1,6 +1,5 @@ <%@ page import="java.util.Random" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@ taglib prefix="ct" uri="/tags" %> ${title} @@ -15,6 +14,5 @@
${m.name} : ${message} (我想静静
- \ No newline at end of file diff --git a/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/resources/templates/helloworld2.jsp b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/resources/templates/helloworld2.jsp new file mode 100644 index 0000000000000000000000000000000000000000..1793a6aa8bb1786ba2305b227b5b52fc92261bd9 --- /dev/null +++ b/solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/test/resources/templates/helloworld2.jsp @@ -0,0 +1,20 @@ +<%@ page import="java.util.Random" %> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="ct" uri="/tags" %> + + + ${title} + + +
+ page path: ${ctx.path()} +
+
+ properties: custom.user :${user} +
+
+ ${m.name} : ${message} (我想静静) +
+ + + \ No newline at end of file