Динамический url rewriting в JSF приложении

243
31 марта 2018, 16:28

Всем привет) Пожалуйста помогите решить задачу.

Условия:

Есть приложение написанное на JavaEE JSF. В приложении есть пользователи, у пользователей есть профиль, соответственно регистрация и идентификация. Приложение в стиле SPA соответственно есть всего две страницы на которых разворачиваются события. Первая эта страница регистрации/логина - my_site.com/login.xhtml, вторая это основная страница приложения - my_site.com/main_page.xhtml.

Задача:

Страница логина стартовая, поэтому также доступна по адресу my_site.com/, а вот страница my_site.com/main_page.xhtml, согласно ТЗ должна быть доступна по адресу - my_site.com/user_name, причем user_name соответственно для каждого юзера свой. Как это реализовать ума не приложу(

Есть замечательные библиотеки prettyfaces и rewrite которые призваны решать подобные вопросы, но к сожалению они только умеют на старте приложения формировать URL из переменной, например так -

<url-mapping id="userName">
    <pattern value="/#{ user.getName() }/"/>
    <view-id value="/main_page.xhtml" /> 
</url-mapping>

Результат мог бы быть положительным и на самом деле страница main_page.xhtml будет доступна по имени нашего пользователя при условии что мы знаем имя пользователя на старте приложения. Но его имя мы получаем из базы, только после того как он залогинился. Видимо урлы определяются во время деплоя приложения на сервер, потому что изменяя значение переменной userName(из примера с xml конфигурацией) нам НЕ становится доступна страница main_page.xhtml по новому имени.

Теперь снова вкратце -

Приложение развернуто и в работе, приходит пользователь на страницу логина, логинится. Мы подтягиваем данные о нем из базы и должны переадресовать его на основную страницу приложения. При этом в адресной строке у него должен быть виден URL состоящий из данных(его имени) которые мы только что получили из базы. Как это реализовать?

Answer 1

Можно воспользоваться ResourceHandler-ом. Не помню с какой версии в JSF появились ResourceHandler-ы, но в последней-то точно есть:)

Сначала составим простенький ResourceHandler:

public class UserPageResourceHandler extends ResourceHandlerWrapper {
    private final ResourceHandler wrapped;
    public UserPageResourceHandler(ResourceHandler wrapped) {
        this.wrapped = wrapped;
    }
    @Override
    public ResourceHandler getWrapped() {
        return wrapped;
    }
    @Override
    public ViewResource createViewResource(FacesContext context, String resourceName) {
        String remoteUser = FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();
        if (remoteUser == null) {
            // если никто не подключился, то ничего особого не предприминать
            return super.createViewResource(context, resourceName);
        }
        // Вычислить название страницы ползователя: /user_name.xhtml
        String userPage = "/" + remoteUser + ".xhtml";
        if (resourceName.equals(userPage)) {
            // тут и подменим /Василий_Пупкин.xhtml на /main_page.xhtml
            // т.е. запрос /Василий_Пупкин.xhtml обрабатывается как /main_page.xhtml
            return super.createViewResource(context, "/main_page.xhtml");
        } else {
            // во всех остальных случаях что запросят, то и выдать
            return super.createViewResource(context, resourceName);
        }
    }
}

Потом пропишем его в faces-config.xml:

<faces-config version="2.2"
    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/web-facesconfig_2_2.xsd">
    <application>
        <resource-handler>my.application.UserPageResourceHandler</resource-handler>
    </application>
</faces-config>

Если не ошибаюсь, /main_page.xhtml можно переместить в /WEB-INF. Чтобы не открывалась прямым запросом в браузере. Тогда надо изменить и код на return super.createViewResource(context, "/WEB-INF/main_page.xhtml");

Вкратце по второму вопросу.

Есть несколько способов.
а) При программной реализации входа через форму кнопка "Войти" может иметь примерно такой action-метод:

public String login() {
    ...
    // Код ниже должен выполняться при успешной аутентификации
    String remoteUser = FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();
    String userPage = "/" + remoteUser + ".xhtml";
    return userPage + "?faces-redirect=true";
}

б) При стандартном способе понадобится ещё одна страница. Пусть это будет index.xhtml. Его и надо указать в качестве wellcome-страницы, как это обычно делается.
Создать страницу index.xhtml с viewAction

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
    <f:metadata>
        <f:viewAction action="#{indexPage.init}"/>
    </f:metadata>
    ...

И сама viewAction такая:

@Named
@RequestScoped
public class IndexPage {
    public String init() {
        String remoteUser = FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();
        String userPage = "/" + remoteUser + ".xhtml";
        return userPage + "?faces-redirect=true";
    }
}

При успешном входе произойдёт два перенаправления вместо одного.
Сначала на index.xhtml и потом уже на user_name.xhtml.
Но пользователь всё равно этого же не заметит.
Только бы заказчик не заметил или не был бы против в крайнем случае.
login.xhtml -> index.xhtml -> user_name.xhtml

READ ALSO
Реализация javax.tools.JavaCompiler для Scala

Реализация javax.tools.JavaCompiler для Scala

Имеется ли реализация javaxtools

176
Добавление в связующую таблицу (many to many) через JDBC?

Добавление в связующую таблицу (many to many) через JDBC?

Есть бд, в ней 2 сущности и связь many to many, создаю DAO для crud операций, далее возникает вопрос, я хочу создать developer и добавить ему skillКак мне добавить...

171
Yandex Map Kit удаление значка &ldquo;Я&rdquo;

Yandex Map Kit удаление значка “Я”

Использую в своем приложении yandex map kitЕсли работает GPS, то на карте появляется значок "Я", который, я так полагаю, перемещается в зависимости...

235
Какие параметры надо указать для h2 базы в xml файле?

Какие параметры надо указать для h2 базы в xml файле?

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

185