JSP программно рендерит - PullRequest
13 голосов
/ 12 ноября 2009

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

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

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

Ответы [ 6 ]

8 голосов
/ 12 ноября 2009

Мне нужен программный рендеринг страницы JSP.

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

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

Редактировать : вы редактировали свой вопрос:

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

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

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

Редактировать 2 : как вы прокомментировали:

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

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

<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 (или любом другом имени хоста / контекста), и вы увидите

We are in first jsp
We are in second jsp

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

5 голосов
/ 12 ноября 2009

Я не совсем уверен, что это то, что вы ищете, но 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 и сохранить их в памяти. Вы можете скачать исходный код по ссылке выше, чтобы увидеть, как работает SwallowingHttpServletResponse.

1 голос
/ 12 ноября 2009

По какой причине вы должны это сделать? Если вам нужно слить 2 JSP-файл для обработки, возможно, используя include Или вам нужны другие идеи? Можете ли вы дать образец о вашем запросе?

1 голос
/ 12 ноября 2009

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

РЕДАКТИРОВАТЬ: пропустили ваши изменения об изменении источника JSP.

Взгляните на org.apache.jasper.compiler.AntCompiler (включен в jasper.jar в Tomcat). Существует защищенный метод generateClass, который вы можете переопределить и поэкспериментировать:)

1 голос
/ 12 ноября 2009

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

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

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

Редактировать: я бы порекомендовал jsp: включить для работы

1 голос
/ 12 ноября 2009

Возможно, вы могли бы использовать Задача Tomcat JspC для муравьев ?

...