2009-11-12 2 views
11

Мне нужно программно отобразить страницу JSP. Насколько я понимаю, JSP должен иметь некоторый компилятор. Вопрос в том, могу ли я использовать этот компилятор по-разному без JspServlet и других? Все, что мне нужно, это документация о том, как использовать JSP-компилятор (например, Jasper).JSP программно визуализировать

Некоторая дополнительная информация может прояснить ситуацию, я думаю. Я не могу использовать стандартный JspServlet. Я хочу изменить исходный JSP до компиляции в некотором роде (объединить два JSP вместе, чтобы быть точным), поэтому мне нужен способ скомпилировать JSP-результат из InputStream (или Reader) с использованием JSP-компилятора напрямую.

Слияние двух JSP - это соответствие требованиям. Вы можете спросить: «Но почему этот парень просто не использует SiteMesh или что-то вроде этого?». Одна из страниц JSP не является статичной. Он предоставляется пользователем и хранится в базе данных. Мы очищаем и проверяем этот формат JSP (пользователи могут использовать только подмножество тегов, и все они не являются стандартными, но созданы специально для них), кэшируют их и так далее. Но теперь нам нужен способ использовать эти JSP-страницы (которые хранятся в памяти) как макеты для всех страниц JSP, которые запрашиваются пользователем.

+1

У меня была аналогичная проблема, и «самое легкое» решение, которое я нашел, это переключение всего проекта на Velocity (или другой механизм шаблонов), где такие задачи тривиальны. Похоже, вы уже слишком далеко в разработке, чтобы делать такие изменения, но просто говорите ... – serg

ответ

8

мне нужно programmaticaly визуализации JSP-страницы.

Каково функциональное требование в конце концов? Вы явно ищете решение в неправильном направлении. Что это, проблема/требование, для которого вы думаете, что это решение? Мы можем придумать лучшие предложения.

Вам, например, нужно только его выход? Если да, то может быть достаточно java.net.URLConnection.

Edit: вы изменяли вопрос:

Я хочу изменить источник JSP перед компиляцией каким-то образом (объединить два JSP вместе, чтобы быть точным), поэтому мне нужен способ, чтобы составить JSP результат от InputStream (или Reader) напрямую с помощью JSP-компилятора.

ОК, это немного более ясным. Но зачем вам это нужно? Что представляют собой эти JSP? Каков конечный результат, который должен использоваться?

Вы, например, просто хотите включить один JSP в другой? Например. включая head.jsp в main.jsp? Если это так, то может быть достаточно <jsp:include>. Или это еще хуже, содержат ли они необработанный код Java с определенным кодом, который вы хотели бы использовать повторно? Если это так, то вам следует использовать простые классы Java и, если необходимо, теги для этого.

Edit 2: как вы прокомментировали:

Но теперь нам нужен способ, чтобы использовать эти страницы JSP (которые магазин находится в памяти, кстати), как макеты для всех страниц JSP что пользователь по запросу

Просто хранить файлы JSP на файловой системы на диске внутри WebContent веб-приложение (в ServletContext#getRealPath() может прийти в помощь здесь) и направить запрос на свой собственный основной файл JSP, который включает в себя два файла JSP, используя для экзамена PLE:

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

Edit 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 

Чтобы сделать его более эффективным, я бы кэшировать все ресурсы и использовать File#exists() для проверьте, сохранена ли конкретная страница на диске.

+0

Хорошо, давайте погрузимся в требования. Слияние двух JSP - это требование макета. Вы можете спросить: «Но почему этот парень просто не использует SiteMesh или что-то вроде этого?». Одна из страниц JSP не является статичной. Он предоставляется пользователем и хранится в базе данных. Мы очищаем и проверяем этот формат JSP (пользователи могут использовать только подмножество тегов, и все они не являются стандартными, но созданы специально для них), кэшируют их и так далее. Но теперь нам нужен способ использовать эти страницы JSP (которые хранятся в памяти, кстати) как макеты для всех страниц JSP, которые пользователь запрашивает. –

+0

Хорошо, это сработает. Но я хочу, чтобы мой JSP выглядел немного чище. Например ... и описания страниц с тегами страницы. Тег страницы сам по себе заменяет макет во время компиляции. Это возможно в некотором роде? –

+0

Просто включите теги в верхней части содержимого JSP. Просто код JSP обычным способом. Все, что вам нужно сделать, это сохранить его в webcontent webapp. См. SSCCE, который я добавил последним. – BalusC

1

Возможно, вы можете использовать Tomcat's JspC ant task?

+0

Не совсем. Мне нужно скомпилировать JSP на стороне сервера. Так что муравьиная задача не то, что я ищу. Но я посмотрю исходный код этой задачи. Может быть, это будет полезно. Спасибо. –

1

JSTL - это всего лишь библиотека тегов, используемых внутри JSP-файлов. Поэтому в этом контексте это не имеет значения.

Поскольку JSP-компилятор преобразует JSP-файлы в Java-сервлеты, я сомневаюсь, что вы можете запустить его напрямую (компилятор фактически ничего не запускает!) Или не отображает в этом случае JSP-файл.

На самом деле довольно сложно понять, что вы действительно ищете.

Изменить: Я бы рекомендовал JSP: включить в работу

+0

Да, упоминание для JSTL неудобно в этом контексте, согласитесь. И вы правы, страницы JSP становятся сервлетами после компиляции. Что мне нужно, это способ самостоятельно составлять страницы JSP для сервлетов.Я могу объяснить свою задачу немного глубже. Мне нужно слить два JSP-файла каким-то образом (из источников), а затем скомпилировать результат. –

+0

Не достаточно ли включить один из JSP-файлов в другой? См. Jsp: include и <%@include%> –

+0

К сожалению, нет. Правила слияния JSP не являются тривиальными. Конечно, это проблема сама, но ... –

1

Если JSP уже был предварительно скомпилирован сервером приложений, вы можете искать сгенерированный файл .class. В Tomcat это должно быть в каталоге $ CONTEXT_ROOT/org/apache/jsp /. Возможно, вы сможете каким-то образом запустить этот класс и сгенерировать свой результат.

EDIT: Пропустили ваше редактирование об изменении источника JSP.

Посмотрите на org.apache.jasper.compiler.AntCompiler (входит в jasper.jar в Tomcat). Существует защищенный метод, называемый 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.