有没有一种简单的方法可以在 JSF 中实现路由?

Is there a simple way to implement routing in JSF?

我正在尝试实现一个 "generic" 视图,其中显示的(部分)内容取决于 URL。例如

如果 /somepath/somepage.xhtml 指向一个不存在的文件,而不是直接进入 404 错误,我想尝试使用通用视图从数据库中检索 /somepath/somepage.xhtml 的内容,/genericview.xhtml,我有类似的东西:

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

如果被支持 bean 找到,将从 tgenericcontent table 输出数据库条目的内容,具体取决于最初请求的 viewId:

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

如果在那个 table 中找不到视图内容,那么将返回标准 404 错误。

我最接近的是克隆 /genericview.xhtml,仅更改文件路径(例如,更改为 /somepath/somepage.xhtml)。但这让我得到了每个视图的文件的一个精确副本,它非常混乱,并且不允许我通过向我的数据库添加一个条目来创建一个新的 url。

如何在不克隆的情况下获得相同的结果/genericview.xhtml

(P.S: 我已经阅读了有关漂亮脸孔的内容,但是没有更简单的解决方案吗?)

为此,通常 servlet filter is being used. PrettyFaces, UrlRewriteFilter and FacesViews 也会这样做。

您可以通过HttpServletRequest#getRequestURI(). You can check the existence of a web resource by ServletContext#getResource() which will return null on non-existent resources. If the resource exists, just continue the request by FilterChain#doFilter(), else forward the request to the generic view by RequestDispatcher#forward()获取请求URI。

总而言之,过滤器可能是这样的:

@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 键控的请求属性。您可以在与视图关联的支持 bean 的 @PostConstruct 中使用它,以便从数据库中提取正确的内容。

String originalRequestURI = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
// ...