JSP программно отображает

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

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

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

Ответ 1

Мне нужно программно отобразить страницу JSP.

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

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

Изменить: вы отредактировали свой вопрос:

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

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

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

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

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

Просто сохраните JSP файлы в файловой системе диска в webapp webcontent (здесь может появиться 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(), чтобы проверить, сохранена ли эта страница на диске.

Ответ 2

Я не совсем уверен, что это то, что вы ищете, но 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.

Ответ 3

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

Ответ 4

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

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

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

Изменить: я бы порекомендовал jsp: include для задания

Ответ 5

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

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

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

Ответ 6

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