Веб-интерфейс пользователя для приложения Java

Я пытаюсь создать веб-интерфейс пользователя для приложения Java. Пользовательский интерфейс будет очень простым, состоящим из одной страницы с формой для запросов пользователей и страницы результатов — вроде поисковой системы Google или Ask.com.

Я хорошо знаком с базовым API Java, но у меня нет большого опыта использования Java для веб-сред (хотя я использовал ASP.NET), поэтому мне нужен совет:

  • Какой сервер веб-приложений мне следует использовать? Обратите внимание, что мой интерфейс очень легкий, и мне просто нужно что-то быстрое, легко запускаемое/сбрасываемое/останавливаемое и (повторно) развернуть мое приложение. Кроме того, мне нужно, чтобы он работал в нескольких средах, а именно в GNU/Linux, Mac OS X и Windows XP/Vista. Кроме того, я использую ant и Eclipse, поэтому было бы здорово, если бы я мог легко добавить несколько целей ant для управления сервером и/или управлять сервером с помощью IDE. Я изучил Tomcat и Jetty, и последний кажется очень легким и простым в установке и развертывании. Это идеально, потому что графический интерфейс предназначен только для демонстрационных целей, и мне, вероятно, потребуется развернуть его на разных компьютерах. Однако Tomcat существует уже очень давно и кажется более зрелым.

  • Что касается веб-страниц, то Java Server Pages выглядят хорошо, так как они кажутся достаточно простыми для того, что я пытаюсь выполнить (обработка формы и вывод результата), но я полностью уши для предложений.

  • У меня также есть еще одно требование, которое требует от меня объяснения «базового» рабочего процесса приложения: по сути, у меня есть класс Engine, у которого есть метод run(String), который будет обрабатывать ввод пользователя и возвращать результаты для отображения. Этот класс является ядром приложения. Теперь я хотел бы создать экземпляр этого класса только один раз, так как он требует много памяти и очень долго запускается , поэтому я хотел бы создать его при запуске приложения/сервера и сохранить эту ссылку для всего диапазона приложения (т.е. до тех пор, пока я не остановлю сервер). Затем для каждого пользовательского запроса я просто вызывал метод run экземпляра Engine и отображал его результаты. Как это можно сделать в Java?


person João Silva    schedule 16.08.2009    source источник


Ответы (7)


  1. Сервер приложений. Вы считаете Tomcat тяжелым с точки зрения времени выполнения, объема обучения или ...? Я бы выбрал что-то, что имеет хорошо налаженную интеграцию с IDE. Итак, Eclipse + Tomcat или Apache Geronimo, возможно, в его WebSphere Community Edition маска сделает свое дело. Из того, что я видел, этого достаточно для того, что вы хотите, и кривые обучения действительно довольно управляемы.
  2. Да JSP. Возможно, вы все же обнаружите, что ваша презентация должна стать немного более сложной. Дополнительные усилия по переходу на JSF могут окупиться — хорошие виджеты, такие как средства выбора даты.
  3. В вашей обработке у вас будет сервлет (или класс действия, если вы используете JSF), этот класс может иметь переменную-член типа Engine, инициализируемую при запуске, а затем используемую для каждого запроса. Следует иметь в виду, что многие пользователи будут обращаться к этому сервлету и, следовательно, к этому движку одновременно. Безопасно ли использовать ваш Engine из более чем одного потока одновременно?

Расширить в этом пункте. При реализации JSP есть две модели, называемые (с некоторой изобретательностью) Модель 1 и Модель 2. См. это объяснение.

В случае с моделью 1 вы склонны помещать код непосредственно в JSP, он выступает в роли контроллера. Лично я, даже имея дело с небольшими, быстро разрабатываемыми приложениями, этого не делаю. Я всегда использую модель 2. Однако, если вы решите, вы можете просто добавить немного Java в свой JSP.

<%  MyWorker theWorker = MyWorkerFactory.getWorker();
    // theWorker.work();
%>

Я бы предпочел иметь такую ​​​​фабрику, чтобы вы могли контролировать создание рабочего. Фабрика будет иметь что-то вроде (чтобы привести очень простой пример)

private static MyWorker s_worker = new MyWorker();
public static synchronized getWorker() {
       return s_worker;
}

В качестве альтернативы вы можете создать рабочего при первом вызове этого метода.

В случае модели 2 у вас, естественно, есть сервлет, в который вы собираетесь поместить некоторый код, так что вы можете просто

private MyWorker m_worker = MyWorkerFactory.getWorker();

Это будет инициализировано при загрузке сервлета. Не нужно беспокоиться о том, чтобы настроить его для загрузки при запуске, вы просто знаете, что он будет инициализирован до того, как будет запущен первый запрос. Еще лучше использовать метод init() сервлета. Это гарантированно вызывается до того, как будут обработаны какие-либо запросы, и это место, спроектированное API сервлета для такой работы.

public class EngineServlet extends HttpServlet {

private Engine engine;

// init is the "official" place for initialisation
public void init(ServletConfig config) throws ServletException {
     super.init(config);
     engine = new Engine();
} 
person djna    schedule 16.08.2009
comment
Спасибо за комментарии. 1) Тяжелый в том смысле, что он имеет много функций, которые мне не нужны, а также требует нескольких дополнительных шагов для установки. С другой стороны, судя по тому, что я видел в Jetty, все, что требуется для его запуска, — это запустить файл java -jar start.jar. Также есть хороший проект contrib, который позволяет мне запускать приложение, просто используя java -jar jetty-runner.jar application.war, что довольно круто, так как я хочу запустить веб-интерфейс в демонстрационных целях на разных компьютерах. Тем не менее, у Tomcat действительно солидная репутация, так что это сложный выбор. - person João Silva; 16.08.2009
comment
2) Это действительно очень простой интерфейс для (довольно) сложного приложения, и я не думаю, что мне действительно понадобятся более продвинутые виджеты, но спасибо за предложение. В конце концов, мне нужно будет интегрировать некоторые API (такие как Google Maps) на странице результатов, но я, вероятно, просто закодирую javascript на странице JSP для этого. - person João Silva; 16.08.2009
comment
3) Можете ли вы привести пример использования JSP? Из того, что я прочитал до сих пор, мне нужно активировать load-on-startup конфигурации сервлета, чтобы он загружался при запуске сервера. Но как именно я могу получить доступ к переменной-члену Engine сервлета изнутри JSP? По сути, у меня есть страница A.jsp с текстовым полем ввода, содержимое которого будет передано с помощью GET на страницу B.jsp. На этой странице мне нужно получить этот экземпляр Engine, вызвать метод, используя содержимое query string, и вывести результаты. - person João Silva; 16.08.2009
comment
Кроме того, что касается проблем с потокобезопасностью, я не делаю много обновлений, за исключением случаев, когда я создаю файл Engine. Все остальное на самом деле просто тяжелая обработка. Однако у меня есть класс, который использует FutureTask для параллелизации некоторых операций, но они просто используют веб-API для сбора и возврата результатов. - person João Silva; 16.08.2009
comment
1). Похоже, Jetty делает то, что вам нужно. Никогда не пользовался, большего сказать не могу. 2). Я понимаю. 3). Добавлено в ответ. Боюсь, что код не проверен, но концепции должны помочь вам начать работу. Основная идея заключается в том, что вы просто используете стандартные правила Java для инициализации классов. - person djna; 16.08.2009

Технология, которую вам нужно изучить, - это спецификация Sun Java Servlet, поскольку именно ее реализуют ВСЕ нетривиальные веб-серверы Java. Это позволяет вам писать сервлеты, которые могут делать все, что вам нужно на стороне сервера. Затем вы можете разрабатывать любой контейнер, который хорошо работает с вашим iDe, и развертывать его на любом другом контейнере, который хорошо работает в производственной среде.

Вам также необходимо изучить базовый HTML, так как в противном случае вам нужно было бы изучить JavaServer Faces или аналогичный, который является довольно большим, чтобы создать кнопку отправки, которая вам нужна, с другими записями в HTML-форме.

Чтобы ваш движок работал, вы можете создать сервлет с синглтоном в web.xml, который вы затем можете вызвать. Будьте абсолютно уверены, что это потокобезопасно, иначе у вас будет много боли. Для начала вы можете объявить свой вызывающий сервлет синхронизированным, чтобы гарантировать, что в любой момент будет активен не более одного вызова run().

person Thorbjørn Ravn Andersen    schedule 16.08.2009
comment
Спасибо за комментарии. Да, я так и думал. Моя цель — иметь легкий контейнер, в котором я могу легко развернуть приложение для демонстрационных целей. Однако в конечном итоге мне может понадобиться постоянно размещать приложение, возможно, используя другой контейнер. Я знаю HTML и другие веб-технологии (CSS/Javascript и т. д.), так как использовал их раньше с ASP.NET. Однако я новичок в разработке веб-приложений на Java. - person João Silva; 16.08.2009
comment
Какой контейнер почти не имеет значения, если вы пишете веб-приложение, совместимое с Java. Tomcat обычно имеет отличную поддержку IDE, которая бесценна при разработке. Сейчас, к сожалению, вам нужно немного поучиться :-) - person Thorbjørn Ravn Andersen; 17.08.2009
comment
Да, я знаю, я читал некоторые статьи на эту тему, не нужно извиняться; ). Кроме того, если вы можете, прокомментируйте код, который я добавил к вопросу. - person João Silva; 17.08.2009

РЕДАКТИРОВАНИЕ. На данный момент я решил следующее:

  • Сервер веб-приложений: Jetty;
  • Страницы сервера Java для представлений;
  • Основываясь на предложениях @djna, я прочитал пару статей о Модели 2 и придумал это решение (которое я еще не тестировал, потому что мне нужно закончить свое приложение перед переходом в интерфейс):

form.jsp

<form action="/servlet/EngineServlet" method="GET">
  <input type="text" name="text" />
</form>

EngineServlet.java

public class EngineServlet extends HttpServlet {
  private Engine engine = new Engine(); 
  // does this make sure engine only gets instantiated one time in the entire lifespan of the web application; from what I've read from the servlet lifecycle, it seems like it, but I'd like to hear opinions

  public void doGet(HttpServletRequest request,
                    HttpServletResponse response) {
    String text = request.getParameter("text");
    ResultBean result = engine.run(text);
    request.setAttribute("result", result);
    RequestDispatcher dispatcher = request.getRequestDispatcher("result.jsp");
    dispatcher.forward(request, response); 
    // what's the difference between forward, and request.sendRedirect() ?
  }    
}

result.jsp

<div>The result was: ${result.text}</div>

Что вы думаете об этом решении? Есть ли проблемы, которые могут быть неочевидны для тех, кто работает с J2SE? Я также написал в комментариях некоторые сомнения, которые у меня есть в коде. Спасибо.

person João Silva    schedule 17.08.2009
comment
Инициализация движка: чище, если это делается в методе сервлета init(), я изменил свой ответ, чтобы сказать это. Жизненный цикл сервлета обсуждается в j2ee.me/j2ee/ tutorial/1_3-fcs/doc/Servlets4.html Вы увидите, что в любой момент времени будет ровно один экземпляр класса сервлета, поэтому в вашем коде будет один экземпляр Engine в один момент времени. время. Сервер приложений может выбрать завершение и повторную инициализацию вашего сервлета. Я никогда не видел, чтобы сервер приложений делал это, но, чтобы быть на 100% уверенным, возложил ответственность за то, чтобы быть синглтоном с движком. Смотрите следующий комментарий. - person djna; 18.08.2009
comment
Может быть важно, чтобы было не более одного экземпляра Engine. Или это может быть очень желательно с точки зрения потребления памяти. В любом случае я бы сказал, что вы не должны полагаться на клиента (в данном случае на сервлет) для контроля за наличием одного экземпляра. Вместо этого используйте фабрику, как показано в моем ответе. Сервет говорит: «Дайте мне двигатель», который завод говорит, используйте этот, и может взять на себя ответственность за использование двигателя Singleton. Это решение устойчиво к необычным событиям жизненного цикла сервлета, а также к будущему обслуживанию. Что произойдет, если у вас есть два сервлета? - person djna; 18.08.2009
comment
Вперед: сервлет выполняет некоторую работу, собирает некоторые данные, а затем передает тот же запрос в JSP для рендеринга. Браузер видит URL-адрес сервлета. Перенаправление: сервер отправляет ответ браузеру, говоря, что не отображать это, вместо этого отправить запрос на эту страницу, другой URL-адрес. Вы используете последний, когда первоначальный запрос выполнял какую-то работу, которую вы не хотите случайно повторить (например, заплатить немного денег). Отправляя перенаправление, история браузера может иметь последовательность запросов отображения GET без действий POST, которые при повторной отправке повторяли бы работу. - person djna; 18.08.2009
comment
Большое спасибо, ваши советы и предложения позволили мне многое узнать о Web/J2EE стороне Java. Я принимаю твой ответ. Просто прокомментируйте, если можете, мою реализацию модели 2 выше, чтобы увидеть, можно ли что-то улучшить. - person João Silva; 18.08.2009

Предполагая, что это не одноразовое приложение, которое не нуждается в каком-либо обновлении/обслуживании в будущем, я бы рекомендовал вам сделать уровень представления с помощью Apache Wicket по следующим причинам (сначала прочитайте краткую информационную аннотацию с главной страницы):

  • Поскольку Wicket отделяет слой представления и работает на уровне модели MVC чистым способом, можно легко объяснить, что представление полностью отделено от остальной части приложения и интерфейс IModel используется для надежной связи данных с уровня контроллера на уровень представления. Таким образом, ваш уровень контроллера может быть единственным синглтоном приложения, если вы используете его таким образом.
  • Код Wicket невероятно прост в обслуживании, также можно очень легко расширить функциональность вашего веб-приложения, поскольку это ООП-фреймворк, а не разметка, смешанная с другими типами разметки, которые выражают код.
person Esko    schedule 16.08.2009
comment
Спасибо за комментарии. Это выглядит аккуратно, но мне просто нужна форма => отправить => процесс => показать результаты, так как это просто для демонстрационных целей приложения. - person João Silva; 16.08.2009

  1. Jetty — это очень легкий контейнер, идеально подходящий для вашего сценария разработки.

  2. Вы можете посмотреть на Wicket для своей стороны рендеринга; вам кажется более удобным выполнять задачи, подобные коду, а не прямой пользовательский интерфейс.

  3. Шаблон, который вы описываете, является шаблоном Singleton. Взгляните на результаты Google для синглтона в java.

person joeslice    schedule 16.08.2009

  1. сервер приложений: кот
  2. веб-страница: JSP
  3. Вам нужен класс Singleton или класс со статическим методом. Слово предостережения: Остерегайтесь состояния гонки. Возможно, вам потребуется использовать ключевое слово synchronized для методов, включающих операцию обновления/изменения.
person janetsmith    schedule 16.08.2009
comment
Вы должны окончательно сообщить веб-контейнеру о небезопасном сервлете потока и управлять им. Syncrhonized позволяет JVM делать это вместо этого, что может привести к неотвечающему веб-контейнеру. - person Thorbjørn Ravn Andersen; 17.08.2009

Это довольно открытый вопрос, и существует огромное количество возможных ответов в зависимости от ваших требований. Стандартный способ написания веб-приложений — использование платформы Java EE, что означает JSP, сервлеты и EJB для бизнес-логики. Однако существует довольно много популярных и действенных альтернатив, таких как Spring, Seam, GWT, и даже более радикальных альтернатив, таких как JRuby on Rails. Похоже, ваши потребности довольно просты, поэтому вы, вероятно, захотите использовать простое решение, такое как Jetty + Servlets + JSP.

Я предполагаю, что ваш движок может обрабатывать несколько одновременных запросов? Если нет, возможно, вы захотите найти способ ставить запросы в очередь, например JMS.

person Ken Liu    schedule 16.08.2009