2009-11-12 88 views
11

我需要以編程方式呈現JSP頁面。據我所知,JSP應該有一些編譯器。問題是我可以直接使用這個編譯器而不使用JspServlet和其他編譯器嗎?我需要的只是文檔如何使用JSP編譯器(例如Jasper)。JSP以編程方式呈現

我想,一些額外的信息將闡明情況。我不能使用標準的JspServlet。我想在編譯之前以某種方式更改源JSP(精確地將兩個JSP合併在一起),所以我需要一種方法來直接使用JSP編譯器從InputStream(或Reader)編譯JSP結果。

兩個JSP的合併是佈局要求。你可以問:「但爲什麼這個人只是不使用SiteMesh或類似的東西?」。其中一個JSP頁面不是靜態的。它由用戶提供並存儲在數據庫中。我們對這個JSP佈局進行了清理和驗證(用戶只能使用標籤的子集,並且它們都不是標準的,而是專門爲它們創建的),緩存它們等等。但是現在我們需要一種方法來將這些JSP頁面(存儲在內存中)用作用戶請求的所有JSP頁面的佈局。

+1

我有一個類似的問題,我發現「最簡單」的解決方案是將整個項目切換到Velocity(或其他模板引擎),在這些任務是微不足道的。看起來你在開發過程中已經太過於做出這樣的改變,但只是說... – serg 2009-11-12 02:25:33

回答

8

我需要programmaticaly渲染的JSP頁面。

究竟是什麼功能要求?你顯然在找錯方向的解決方案。它是什麼,你認爲這是解決方案的問題/要求?我們可能會提出更好的建議。

例如,您是否需要其輸出?如果是這樣,那麼java.net.URLConnection就足夠了。

編輯:您編輯您的問題:

我想在編譯之前修改源JSP以某種方式(合併兩個JSP在一起,要準確),所以我需要一種方法來編譯JSP結果從InputStream(或Reader)直接使用JSP Compiller。

OK,這是一個更加清晰。但是,你需要這個嗎?這些JSP實際上代表什麼?應該使用的最終結果是什麼?

例如,您是否想要在其他JSP中包含一個JSP?例如。包括一個head.jspmain.jsp?如果是這樣,那麼<jsp:include>就足夠了。或者更糟糕的是,它們是否包含原始Java代碼和一些您想要重用的特定代碼?如果是這樣,那麼你應該使用普通的Java類,如果必要的話使用taglibs。

編輯2:當你說:

但現在我們需要一種方式來使用這些JSP頁面(這是儲存在內存中的方式)作爲佈局的所有JSP頁面用戶請

只存儲web應用程序的web內容的內部磁盤文件系統上的JSP文件(ServletContext#getRealPath()可能會進入救援在這裏),並轉發給自己的主JSP文件的請求使用的考試,其中包括兩個JSP文件PLE:

<jsp:include page="${page1}" /> 
<jsp:include page="${page2}" /> 

編輯3:我創建了一個SSCCE證明其工作。

package mypackage; 

import java.io.BufferedWriter; 
import java.io.File; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.OutputStreamWriter; 

import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

public class TestServlet extends HttpServlet { 

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
     throws ServletException, IOException 
    { 
     File root = new File(getServletContext().getRealPath("/")); 

     String main = "<jsp:include page=\"${page1}\" /><jsp:include page=\"${page2}\" />"; 
     write(main, new File(root, "main.jsp")); 

     String page1 = "<p>We are in ${data1}"; 
     write(page1, new File(root, "page1.jsp")); 
     request.setAttribute("page1", "page1.jsp"); 
     request.setAttribute("data1", "first jsp"); 

     String page2 = "<p>We are in ${data2}"; 
     write(page2, new File(root, "page2.jsp")); 
     request.setAttribute("page2", "page2.jsp"); 
     request.setAttribute("data2", "second jsp"); 

     request.getRequestDispatcher("main.jsp").forward(request, response); 
    } 

    private static void write(String content, File file) throws IOException { 
     BufferedWriter writer = null; 
     try { 
      writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); 
      writer.write(content); 
     } finally { 
      if (writer != null) try { writer.close(); } catch (IOException ignore) {} 
     } 
    } 

} 

http://localhost:8080/playground/test(或者你使用任何主機/ CONTEXTNAME)執行它,你會看到

We are in first jsp 
We are in second jsp 

爲了更高效的I能緩存一切資源和利用File#exists()到檢查特定頁面是否已經保存在磁盤上。

+0

好吧,讓我們深入瞭解需求。兩個JSP的合併是佈局要求。你可以問:「但爲什麼這個人只是不使用SiteMesh或類似的東西?」。其中一個JSP頁面不是靜態的。它由用戶提供並存儲在數據庫中。我們對這個JSP佈局進行了清理和驗證(用戶只能使用標籤的子集,並且它們都不是標準的,而是專門爲它們創建的),緩存它們等等。但是現在我們需要一種方法來將這些JSP頁面(即存儲在內存中的頁面)用作用戶請求的所有JSP頁面的佈局。 – 2009-11-12 02:08:47

+0

好吧,它會工作。但是我希望我的JSP看起來更乾淨一些。像 ...和頁面標籤的子頁面描述頁面。自身的頁面標籤取代了編譯時的佈局。這在某種程度上可能嗎? – 2009-11-12 02:24:08

+0

只需在JSP內容的頂部包含taglibs即可。只需按照常規方式編寫JSP代碼。所有你需要做的就是將它存儲在webapp的webcontent中。查看我上次添加的SSCCE。 – BalusC 2009-11-12 02:34:50

1

也許你可以使用Tomcat's JspC ant task

+0

不完全。我需要自己編譯服務器端的JSP。所以螞蟻的任務不是我想要的。但我會看看這個任務的源代碼。也許這將是有益的。謝謝。 – 2009-11-12 01:39:35

1

JSTL只是JSP文件中使用的標籤庫。所以在這方面真的沒關係。由於JSP編譯器將JSP文件轉換爲Java Servlet,我懷疑你可以讓它直接運行(編譯器實際上不會運行任何東西!),或者爲此提供一個JSP文件。

實際上很難從你的問題中理解你真正需要的東西。

編輯:我會建議JSP:包括作業

+0

是的,在這方面提及JSTL是不方便的,同意。 而你說得對,JSP頁面在編譯之後變成了servlet。我需要的是一種自己編譯JSP頁面到servlet的方法。我可以更深入地解釋我的任務。我需要以某種方式(從源代碼)合併兩個JSP文件,然後編譯結果。 – 2009-11-12 01:51:31

+0

將其中一個JSP文件包含在其他文件中是不夠的?參見jsp:include和<%@include%> – 2009-11-12 01:59:02

+0

不幸的是,沒有。 JSP合併的規則不是微不足道的。這是自己的問題,但... – 2009-11-12 02:01:53

1

如果JSP已經被appserver預編譯,那麼您可以查找生成的.class文件。在Tomcat中,這應該在$ CONTEXT_ROOT/org/apache/jsp /目錄下。你可能能夠以某種方式運行這個類並生成你的輸出。

編輯:錯過了關於修改JSP源代碼的編輯。

看看org.apache.jasper.compiler.AntCompiler(包含在Tomcat的jasper.jar中)。有一種名爲generateClass的受保護方法,您可能可以覆蓋並篡改:)

1

您需要這樣做的原因是什麼? 如果您需要合併2個jsp文件進行處理,也許使用包括 或者您需要其他想法?你可以提供關於你的請求的樣本嗎?

4

我不完全確定這是否是您要查找的內容,但DWR framework包含一個稱爲WebContext.forwardToString的方法,該方法將當前請求以及假響應對象轉發給URL,然後將緩衝區的內容讀取到內存中。下面的代碼示例:

StringWriter sout = new StringWriter(); 
StringBuffer buffer = sout.getBuffer(); 

HttpServletResponse realResponse = getHttpServletResponse(); 
HttpServletResponse fakeResponse = new SwallowingHttpServletResponse(realResponse, sout, realResponse.getCharacterEncoding()); 

HttpServletRequest realRequest = getHttpServletRequest(); 
realRequest.setAttribute(WebContext.ATTRIBUTE_DWR, Boolean.TRUE); 

getServletContext().getRequestDispatcher(url).forward(realRequest, fakeResponse); 

return buffer.toString(); 

您可以使用它來獲得JSP rednering的結果,並將其存儲在內存中。你可以從上面的鏈接下載源代碼,看看SwallowingHttpServletResponse是如何工作的。

相關問題