2011-12-16 2 views
4

У меня есть довольно стандартный веб-приложение работает под Tomcat 7.Tomcat JSP/JSTL без HTTP

То, что я сейчас пытаюсь сделать, это рычаги JSP/JSTL как язык шаблонного независимо от HTTP/обслуживание сети аспектов Tomcat для создания HTML, который можно отправить по электронной почте и преобразовать в PDF.

Кто-нибудь еще пытался сделать это раньше и мог помочь мне с некоторыми указателями?

Заранее благодарен.

+0

Да; Я знаю все о Velocity и FreeMarker. Это JSP, в котором я интересуюсь. – Kong

+0

См. Также http://stackoverflow.com/questions/1075827/execute-jsp-directly-from-java – Raedwald

ответ

8

В отличие от того, что Стивен C сказал, да, JSP - сервлеты и т. Д. И т. Д. (И скорость довольно хорошая и простая в использовании)

Но что такое сервлет?

Это интерфейс. Интерфейс с одним основным методом:

service(ServletRequest req, ServletResponse res) 

Найдите класс JSP, приведение его в сервлет, создавать реализации 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. Но, скорее всего, вам, вероятно, понадобится немного больше, чем атрибуты и потоки. Если вы вернете ответ, StringWriter, вы на полпути.

Следующая часть представляет собой сервлет из JSP. Удобно, компилятор Jasper делает это для вас - игра вызывает его. Я никогда не делал этого напрямую, но это явно можно сделать, так как это делает контейнер сервлетов, а также файл JSPC/bat-файл, муравьиная задача, а также большинство контейнеров Servlet, использующих Jasper. Итак, это можно сделать. Когда вы знаете, как это вызывать, вы узнаете окончательное имя сгенерированного класса для JSP. (См. Первую строку образца.)

Я когда-нибудь это делал? Нет. Но я держал пари в течение менее чем одного дня беспорядка вокруг, вы узнаете, это выполнимо или нет. Я держу пари, что это так, особенно если вы не запуститесь в какой-либо классный загрузчик shenanigans. У вас может возникнуть проблема, если вы позволите своим пользователям изменять и восстанавливать JSP (поэтому MyEmail.jsp компилируется в MyEmail.class, MyEmail_2.class и т. Д.). Но если вы вызовете Джаспера самостоятельно, у вас, скорее всего, будет больше контроля над этим. Другая сложная часть - это определение имени класса JSP. Большинство контейнеров следуют базовому шаблону здесь, поэтому, если вы соскучитесь в сгенерированном коде из WAR, вы, скорее всего, найдете его.

Держите JSP разумно простыми (и шаблон электронной почты не должен быть слишком сложным со встроенной Java или чем-либо, что делает случайные вызовы), и это еще более хороший шанс, что он будет работать.

Ваше решение не может быть переносимым из коробки Tomcat, но вам, вероятно, все равно. Люди, с которыми я разговаривал, используют JSP для шаблонов, просто открыли сокет на свой собственный сервер и сделали запрос. Они тоже не зашли так далеко.

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

поредактирует поредактируют поредактирую все!

Addenda:

Таким образом, для всех скептиков ...

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 часа в отладчике будет делать для вас.

Я создал простой JSP в /tmp/app/newjsp.jsp.

jspc.setUriroot сообщает компилятору, где находится база вашего «веб-приложения». jspc.setOutputDir сообщает jspc, куда помещать сгенерированные файлы Java и Class. jspc.setJspFiles сообщает jspc, какие файлы нужно компилировать, основываясь на корне URI. 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 - ничего. Но среда выполнения требовала сеанса, она просто не использует ее сама по себе для моего очень простого JSP, и я не был мотивирован на начинку в том, что был из Servlet.

Я проверил это на Glassfish v2.1. Я просто добавил appserv_rt.jar (из glassfish/lib) в мой путь к классу сборки (чтобы он мог найти банки JspC), но я не собираю его в WAR (поскольку он уже находится в контейнере).

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

Я бы также использовал приватный URLClassLoader для загрузки поддельных классов JSP.Если я ПОНИМАЮ, я бы никогда не перезагрузил JSP, а просто сделал бы адрес моей директории WEB-INF/classes и предоставил бы ей собственный пакет и давал бы системе загрузить их.

Но, да, это сработало. Ничего страшного. Это просто java.

+1

Могу ли я, ??? –

+0

@MK - нет, вы не можете :-) –

3

Это не имеет смысла. JSP - это хороший синтаксис, который приводит к генерации класса сервлетов Java EE. Действительно, «сервлет»/«http» характер JSP тщательно переплетается через API и семантическую модель JSP и JSTL.

Если вы хотите генерировать HTML независимо от веб-запросов, вам лучше использовать другую технологию шаблонов; например Velocity или FreeMarker. Если вы хотите, чтобы HTML был доставлен как веб-ответы, а также, чтобы ваши сервлеты вызывали механизм шаблонов для генерации ответов. (Если вы используете Spring, для этого существует существующая инфраструктура. Другие фреймворки могут иметь схожую поддержку, но если нет, для этого не должно быть сложно реализовать какой-либо код для клея.)