Есть ли простой способ реализовать маршрутизацию в JSF?

Я пытаюсь реализовать «общий» вид, в котором (часть) отображаемого контента зависит от URL-адреса. Например.

Если /somepath/somepage.xhtml указывает на несуществующий файл, вместо того, чтобы сразу перейти к ошибке 404, я хочу попытаться получить содержимое /somepath/somepage.xhtml из базы данных, используя общее представление, /genericview.xhtml, где у меня есть что-то вроде:

<h:outputText value="#{genericViewBean.content_lg}"
                escape="false" />

который, если он будет найден вспомогательным компонентом, выведет содержимое записи базы данных из таблицы tgenericcontent в зависимости от первоначально запрошенного viewId:

 webpath                              | content
 /somepath/somepage.xhtml             | <p>This is a test</p>
 /someotherpath/someotherpage.xhtml   | <p>A different test</p>

Если содержимое представления не найдено в этой таблице, будет возвращена стандартная ошибка 404.

Ближе всего мне удалось клонировать /genericview.xhtml, изменив только путь к файлу (например, на /somepath/somepage.xhtml). Но это дает мне одну точную копию файла для каждого представления, это довольно беспорядочно и не позволяет мне создать новый URL-адрес, просто добавив запись в мою базу данных.

Как я могу получить тот же результат без клонирования /genericview.xhtml?

(P.S. Я читал о милолицых, но нет ли более простого решения?)


person NotGaeL    schedule 12.01.2015    source источник
comment
Итак... передний контроллер? Мало чем отличается от того, что FacesServlet уже делает? Prettyfaces или написание собственного фронт-контроллера (который должен соответствовать либо существующей странице, либо сервлету) — практически единственные ваши варианты. В вашем собственном фронт-контроллере теперь у вас есть гибкость для отправки запроса в соответствующее представление с использованием различных механизмов.   -  person kolossus    schedule 13.01.2015
comment
учитывая варианты, вероятно, лучше всего, если я разверну симпатичные лица и настрою Faces-config, перенаправляющий путь /dynamic/* на /genericview.xhtml?path=* или что-то в этом роде...   -  person NotGaeL    schedule 13.01.2015


Ответы (1)


Для этого обычно используется фильтр сервлета. PrettyFaces, UrlRewriteFilter и FacesViews также делают это таким же образом.

Вы можете получить URI запроса с помощью HttpServletRequest#getRequestURI() . Вы можете проверить наличие веб-ресурса с помощью ServletContext#getResource(), который вернет null для несуществующих ресурсов. Если ресурс существует, просто продолжите запрос с помощью FilterChain#doFilter(), в противном случае перенаправьте запрос в общее представление с помощью RequestDispatcher#forward().

В общем, вот как может выглядеть фильтр:

@WebFilter("/*")
public class GenericViewFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        String relativeRequestURI = request.getRequestURI().substring(request.getContextPath().length());

        boolean resourceExists = request.getServletContext().getResource(relativeRequestURI) != null;
        boolean facesResourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER));

        if (resourceExists || facesResourceRequest) {
            chain.doFilter(request, response);
        }
        else {
            request.getRequestDispatcher("/genericview.xhtml").forward(request, response);
        }
    }

    // ...
}

В /genericview.xhtml исходный URI запроса доступен как атрибут запроса с ключом RequestDispatcher#FORWARD_REQUEST_URI. Вы можете использовать его в @PostConstruct вспомогательного компонента, связанного с представлением, чтобы извлечь нужный контент из БД.

String originalRequestURI = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
// ...
person BalusC    schedule 13.01.2015
comment
Хотя я уже реализовал очень простой класс поставщика конфигурации Rewrite (ocpsoft.org/rewrite) ( Ребята из prettyfaces определенно придумали отличного преемника prettyfaces: только одна дополнительная зависимость от моего pom и реализация класса провайдера конфигурации в моем проекте, чтобы все было готово без каких-либо дополнительных изменений), ваш ответ описывает именно то, что я искал за. Большое спасибо! - person NotGaeL; 14.01.2015