В этот раз у нас появится Java-код. Будем писать форму и логику обработки введенных данных. Пост НЕ для тех, кто знает что такое JSF 2 и/или JSF 1.2, а faces-config.xml — не просто файл в проекте. Смотрите, я предупреждал…
С версии JSF 2.3.0 стандартная аннотация
В файл
Создадим файл
Создадим файл
В файл
Теперь вместо
Больше к CDI мы возвращаться не будем!
Теперь давайте напишем немного кода. Нам потребуется 2 класса — в 1-ом мы будем передавать данные, во 2-ом будет функция обработки этих данных.
Класс-данных
Класс-обработчик
Если с
Тут все просто! В файл
Запускаем:
Проверяем:
На дворе 2017 год, а формы все еще без AJAX?! В файл
Что изменилось:
Про
Проект все еще очень скромен в своих возможностях, но я буду продолжать!
CDI
С версии JSF 2.3.0 стандартная аннотация
@ManagedBean признана устаревшей. Т.е. чтобы обратиться к своему Java-коду из формы нам потребуется добавить в проект CDI (Context and Dependency Injection) — Weld.В файл
pom.xml добавляем:<dependencies> ... <dependency> <groupId>org.jboss.weld.servlet</groupId> <artifactId>weld-servlet</artifactId> <version>2.4.3.Final</version> </dependency> </dependencies>
Создадим файл
/src/main/webapp/WEB-INF/beans.xml:<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" bean-discovery-mode="all"> </beans>
Вредный совет
В комментариях к прошлому посту заметили:
ОК! В файл
Запускаем:
Читаемtraceback почему не работает.
Там прям особая специфика в регистрации listener'а?
ОК! В файл
/src/main/webapp/WEB-INF/web.xml добавляем:<web-app ... <listener> <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class> </listener> ... </web-app>
Запускаем:
mvn jetty:runЧитаем
Создадим файл
/src/main/webapp/WEB-INF/jetty-env.xml:<?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> <Configure id="webAppCtx" class="org.eclipse.jetty.webapp.WebAppContext"> <Call name="prependServerClass"> <Arg>-org.eclipse.jetty.server.handler.ContextHandler</Arg> </Call> <Call name="prependServerClass"> <Arg>-org.eclipse.jetty.servlet.FilterHolder</Arg> </Call> <Call name="prependServerClass"> <Arg>-org.eclipse.jetty.servlet.ServletContextHandler</Arg> </Call> <Call name="prependServerClass"> <Arg>-org.eclipse.jetty.servlet.ServletHolder</Arg> </Call> <New id="BeanManager" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg> <Ref id="webAppCtx"/> </Arg> <Arg>BeanManager</Arg> <Arg> <New class="javax.naming.Reference"> <Arg>javax.enterprise.inject.spi.BeanManager</Arg> <Arg>org.jboss.weld.resources.ManagerObjectFactory</Arg> <Arg/> </New> </Arg> </New> </Configure>
В файл
/src/main/webapp/WEB-INF/web.xml добавляем:<web-app ... <resource-env-ref> <resource-env-ref-name>BeanManager</resource-env-ref-name> <resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type> </resource-env-ref> ... </web-app>
Теперь вместо
@ManagedBean будет работать @Named. Учитывая что CDI штука хорошая, а с версии JSF 2.3.0 — критичная, стоит понимать что CDI в JSF используется по своему прямому назначению и к JSF непосредственно отношения не имеет.Больше к CDI мы возвращаться не будем!
Классы FormData и FormCtrl
Теперь давайте напишем немного кода. Нам потребуется 2 класса — в 1-ом мы будем передавать данные, во 2-ом будет функция обработки этих данных.
Отступление
С точки зрения реализации — не обязательно выделять логику формы в 2 отдельных класса, но это «правильно» как с точки зрения тестирования, так и сточки зрения архитектуры.
Класс-данных
/src/main/java/ru/habr/FormData.java:package ru.habr; import javax.enterprise.context.RequestScoped; import javax.inject.Named; @Named @RequestScoped public class FormData { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
Класс-обработчик
/src/main/java/ru/habr/FormCtrl.java:package ru.habr; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.inject.Named; @Named @RequestScoped public class FormCtrl { @Inject FormData formData; public String doAction() { // Очень полезные действия с данными... System.out.println(formData.getUsername()); System.out.println(formData.getPassword()); return null; } }
Если с
FormData все понятно, то на FormCtrl стоит взглянуть пристальней:- Благодаря
@Inject, данные формы будут доступны в классе-обработчике в полеformData. - Рекомендую придерживаться тезиса «метод-обработчик должен возвращать строку» хоть это и не обязательно. Строка в дальнейшем используется в навигации, но об этом позже.
Форма
Тут все просто! В файл
/src/main/webapp/index.xhtml добавляем:<h:body> ... <h:form id="habrForm"> <h:inputText value="#{formData.username}"/><br/> <h:inputSecret value="#{formData.password}"/><br/> <h:commandButton action="#{formCtrl.doAction}" value="Send"> </h:commandButton> </h:form> </h:body>
Запускаем:
mvn jetty:runПроверяем:
http://127.0.0.1:8080/AJAX
На дворе 2017 год, а формы все еще без AJAX?! В файл
/src/main/webapp/index.xhtml внесем пару правок:<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"> ... <h:body> ... <h:inputText value="#{formData.username}"/><br/> <h:inputSecret value="#{formData.password}"/><br/> <h:commandButton action="#{formCtrl.doAction}" value="Send"> <f:ajax execute="@form" render="@form"/> </h:commandButton> </h:body> </html>
Что изменилось:
- Добавилось определение библиотеки тегов
xmlns:f="http://xmlns.jcp.org/jsf/core". Без этого можно реализовать AJAX, но обрабатывать придется ручками, что долго и неблагодарно. - Внутри
h:commandButtonпоявился<f:ajax execute="@form" render="@form"/>. Вexecute— указываем что необходимо отправить на сервер (всю форму/все поля формы), вrender— что необходимо обновить с сервера после выполнения AJAX.
Про
f:ajax можно писать отдельный. Сейчас достаточно знать только что с его помощью можно отправить/обновить не только текущую форму на странице, а любой элемент страницы.Послесловие
Проект все еще очень скромен в своих возможностях, но я буду продолжать!
