![](/img/trans.png)
[英]Apache Tomcat 10.0.0-M1 using JSP Absolute uri http://java.sun.com/jsp/jstl/core cannot be resolved
[英]Tomcat JSP/JSTL without HTTP
我有一個在Tomcat 7下運行的非常標准的Web應用程序。
我現在要做的是利用JSP / JSTL作為獨立於Tomcat的HTTP / Web服務方面的模板語言來生成可以通過電子郵件發送並轉換為PDF的HTML。
有沒有其他人試圖這樣做,可以幫助我一些指示?
提前致謝。
與Stephen C所說的相反,是的,JSP是Servlets等等(並且Velocity非常好且易於使用)
但是,什么是Servlet?
這是一個界面。 一個主要方法的接口:
service(ServletRequest req, ServletResponse res)
找到JSP類,將其轉換為Servlet,創建ServletRequest和ServletResponse的實現,然后......
String jspClassName = findJspClassForJSP("your.jsp");
Class jspClass = Class.forName(jspClassName);
Servlet jspServlet = (Servlet)jspClass.newInstance();
MyServletRequest req = new MyServletRequest();
MyServletResponse resp = new MyServletResponse();
jspServlet.init();
jspServlet.service(req, resp);
jspServlet.destroy();
String results = reps.getContent();
這會有用嗎? 好吧,經過一些工作,它會。 顯然,您需要實現ServletRequest / Response的最小外觀以及您需要的JSP。 但是,您可能只需要屬性和流量。 如果你讓你的Response返回一個StringWriter,你就到了一半。
下一部分是從JSP創建servlet。 很方便,Jasper編譯器為您做到了 - 游戲正在調用它。 我從來沒有直接完成它,但顯然可以完成,因為servlet容器都可以完成它,以及JSPC腳本/ bat文件,ant任務,以及大多數使用Jasper的Servlet容器。 所以,那可以做到。 一旦你知道如何調用它,你就會知道JSP的最終生成的類名。 (參見樣本的第一行。)
我做過這個嗎? 不。但我打賭在不到一天的時間里,你會知道這是否可行。 我敢打賭,特別是如果你沒有參加任何類加載器惡作劇。 如果讓用戶更改並重新生成JSP,那么您可能會遇到問題(因此MyEmail.jsp會被編譯到MyEmail.class,MyEmail_2.class等)。 但是如果你自己調用Jasper,你可能會對此有更多的控制權。 另一個難點是確定JSP的類名。 大多數容器都遵循這里的基本模式,因此如果您在WAR生成的代碼中找到它,您可能會發現它。
保持JSP相當簡單(並且電子郵件模板不需要超級復雜的嵌入式Java或任何隨機調用),它更有可能工作。
您的解決方案可能無法從Tomcat開箱即用,但您可能不會關心。 我與之交談的人使用JSP作為模板,只需打開一個套接字到他們自己的服務器並提出請求。 他們也沒走這么遠。
但從表面上看,保存一些糟糕的類裝載機黑洞地獄,我打賭你可以很快地使用它。 盡可能少地執行請求和響應,打幾個NPE作為JSP和JSTL調用你沒有計划的東西,並且正如聖誕老人所說,
劈開,劈開,劈開所有!
附加物:
所以,對於所有的反對者......
public void runJsp() {
JspC jspc = new JspC();
jspc.setUriroot("/tmp/app");
jspc.setOutputDir("/tmp/dest");
jspc.setJspFiles("newjsp.jsp");
jspc.setCompile(true);
try {
jspc.execute();
Class cls = Class.forName("org.apache.jsp.newjsp_jsp");
Servlet s = (Servlet) cls.newInstance();
MyRequest req = new MyRequest();
MyResponse resp = new MyResponse();
s.init(getServletConfig());
s.service(req, resp);
s.destroy();
System.out.println(resp.getSw().toString());
} catch (JasperException ex) {
throw new RuntimeException(ex);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (ServletException ex) {
throw new RuntimeException(ex);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
令人驚訝的是,調試器中的源代碼和1/2小時將為您做什么。
我在/tmp/app/newjsp.jsp中創建了一個簡單的JSP。
jspc.setUriroot告訴編譯器“web app”的基礎所在的位置。 jspc.setOutputDir告訴jspc將生成的Java和Class文件放在何處。 jspc.setJspFiles根據URI Root告訴jspc要編譯哪些文件。 jspc.setCompile告訴它實際編譯代碼。 最后,jspc.execute()執行契約。
默認情況下,Jasper使用包org.apache.jsp,並根據JSP文件名創建一個新類。 對於我的簡單實驗,我只需將“/ tmp / dest”放到我的Glassfish容器的類路徑上,這樣容器就可以找到生成的類。
我加載類,並獲得一個實例。
最后,我創建了MyRequest,MyRequest,最終創建了MySession。 我的IDE方便地為各個接口創建了存根。 在這種情況下,我實現了:MyRequest.getSession(),MyResponse.setContentType(),MyResponse.setBufferSize()和MyResponse.getWriter()。
public PrintWriter getWriter() throws IOException {
if (sw == null) {
sw = new StringWriter();
pw = new PrintWriter(sw);
}
return pw;
}
顯然,sw和pw是MyResponse的實例變量。
MyRequest返回了MySession的一個實例。 我對MySession的實現確實沒有。 但是運行時需要一個Session,它本身並不是為了我的非常簡單的JSP而單獨使用它,而且我沒有動機從Servlet中填充它。
我在Glassfish v2.1上測試了這個。 我只是將appserv_rt.jar(來自glassfish / lib)添加到我的構建類路徑(因此它可以找到JspC jar),但我沒有將它捆綁在WAR中(因為它已經在容器中)。
而且,shazam,它的工作原理。 在“現實生活”中,假設想要利用JSP的進程實際上來自Web請求,我只需創建一個HttpServletResponseWrapper並覆蓋之前的三種方法,其余的可能就是Just Work。 如果Web請求根本不在圖片中,那么您需要創建自己的Session實現(真的沒什么大不了的,它只是一張地圖)。
我還使用私有URLClassLoader來加載虛假的JSP類。 如果我知道我永遠不會重新加載JSP,那么只需將目標作為我的WEB-INF / classes目錄並給它自己的包並讓系統加載它們。
但是,是的,它有效。 沒什么大不了。 這只是java。
這沒有多大意義。 JSP是一種很好的語法,可以生成Java EE servlet類。 實際上,JSP的“servlet”/“http”特性通過API和JSP和JSTL的語義模型完全交織在一起。
如果您想獨立於Web請求生成HTML,那么您最好使用不同的模板技術; 例如Velocity或FreeMarker。 如果您希望HTML也作為Web響應傳遞,請安排您的servlet調用模板引擎來生成響應。 (如果你使用的是Spring,那么現有的基礎設施就可以了。其他框架可能有類似的支持,但如果沒有,那么自己實現一些粘合代碼並不難。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.