2011-12-16 58 views
4

我已經在使用Tomcat下運行的非常標準的web應用程序7.Tomcat的JSP/JSTL不HTTP

什麼我現在要做的是利用JSP/JSTL作爲模板語言無關的HTTP /網絡服務方面的的Tomcat生成可以通過電子郵件發送並轉換爲PDF的HTML。

有任何人嘗試過這樣做,可以幫助我一些指點?

在此先感謝。

+0

是的;我知道所有關於Velocity和FreeMarker - 這是我感興趣的JSP。 – Kong 2011-12-24 01:39:03

+0

參見http://stackoverflow.com/questions/1075827/execute-jsp-directly-from-java – Raedwald 2014-05-14 18:52:58

回答

8

相比之下什麼斯蒂芬c。所述,是的,JSP是Servlet的,等等,等等(和速度是相當不錯的,易於使用)

但是,什麼是一個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會告訴編譯器您的「網絡應用程序」所在的位置。 jspc.setOutputDir告訴jspc放置生成的Java和Class文件的位置。 jspc.setJspFiles通知jsp​​c根據URI Root來編譯哪些文件。 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。

3

這沒有什麼意義。 JSP是一種很好的語法,可以生成Java EE servlet類。事實上,JSP的「servlet」/「http」特性通過API和JSP和JSTL的語義模型徹底交織在一起。

如果你想獨立的Web請求的生成HTML,你會使用不同的模板技術的更好;例如速度或FreeMarker。如果您希望HTML也作爲Web響應提供,請安排您的servlet調用模板引擎來生成響應。 (如果你正在使用Spring有現有的基礎設施這一點。其他的框架可能有類似的支持,但如果沒有,它不應該是很難實現一些膠水代碼自己做到這一點。)