简体   繁体   English

如何在JSF中使用应用程序模式

[英]How to work with application modes in JSF

My application (JSF 2, Java 6, JBoss 7.1) has to offer two operating modes: accessibility mode and non-accessibility mode. 我的应用程序(JSF 2,Java 6,JBoss 7.1)必须提供两种操作模式:可访问性模式和非可访问性模式。

In accessibility mode, some (not all) pages have a particular design to be better read by a screen reader. 在可访问性模式中,一些(并非所有)页面具有特定设计以便屏幕阅读器更好地读取。 The difference between the two modes is purely visual, the managed beans are precisely the same. 两种模式之间的区别纯粹是视觉上的,托管bean完全相同。 Ideally, no Java code has to be changed. 理想情况下,不需要更改Java代码。

Most of the work is done: 大部分工作已经完成:

  1. A link in the page top was added to switch between modes 添加了页面顶部的链接以在模式之间切换
  2. A backing bean was added to handle the click on the link 添加了一个支持bean来处理链接上的点击
  3. When accessibility is turned on, an attribute is added to the session cookie in order to mark it to be accessible 启用辅助功能后,会将属性添加到会话cookie,以便将其标记为可访问
  4. A ResourceResolver was added to rewrite the pages path to the accessible version when accessibility is on for a certain request from a certain user 添加了ResourceResolver,当某个用户发出特定请求的可访问性时,重写可访问版本的页面路径

With all that, it works almost perfectly, but it seems there is some kind of view cache that breaks my solution. 尽管如此,它几乎完美地工作,但似乎有某种视图缓存会破坏我的解决方案。 Consider the scenario below: 考虑以下场景:

  1. Application starts in non-accessibility mode 应用程序以非可访问性模式启动
  2. I navigate along some pages 我浏览了一些页面
  3. I turn accessibility mode on by clicking the corresponding link 我通过单击相应的链接打开辅助功能模式
  4. I receive a page telling me I'm now in accessibility mode and I notice that the menu has changed to its accessibility version (a different component existing in a different page template) 我收到一个页面,告诉我我现在处于辅助功能模式,我注意到菜单已更改为其辅助功能版本(不同页面模板中存在的其他组件)
  5. I navigate to non-visited pages and they all are in accessibility mode 我导航到非访问页面,它们都处于辅助功能模式
  6. I navigate to pages visited before turning accessibility to on and I see them in non-accessibility version 在导入可访问性之前,我导航到访问过的页面,我在非可访问性版本中看到它们

In the last step we can understand that, even in accessibility mode and with the resource path translation happening (I have logs to proof), the pages are generated as they were in the default, non-accessibility mode. 在最后一步中,我们可以理解,即使在可访问性模式中并且发生资源路径转换(我有记录到证明),页面也会以默认的非可访问性模式生成。

So, is really there a pages cache in JSF? 那么,JSF中真的有页面缓存吗? How can I clear it, so the pages will indeed be rendered again? 我怎样才能清除它,所以页面确实会再次渲染?

Update 1 更新1

A network monitoring showed me that the request is indeed issued to the application, so no browser cache is playing here. 网络监控向我显示该请求确实已发布到应用程序,因此此处没有浏览器缓存。

After some time I could finally find a solution, which means, a coding strategy that satisfies all the requirements I had. 过了一段时间,我终于可以找到一个解决方案,这意味着一个满足我所有要求的编码策略。 Maybe it's not a technically good solution, but it is a functinal solution in the sense it produces the experience I needed to provide, saving me to touch all already existing my Java code. 也许这不是一个技术上很好的解决方案,但它是一个功能上的解决方案,因为它产生了我需要提供的体验,使我能够触及所有现有的Java代码。 There it goes! 它去了!

1. A managed bean to flip and flop the accessibility mode 1.托管bean,用于翻转和翻转辅助功能模式

The managed bean below is responsible to turn the accessibility on and off in response to the users click on a certain command link. 下面的托管bean负责响应用户点击某个命令链接来打开和关闭可访问性。 The idea is to add an attribute to the session when the accessibility mode is turned on and remove it when the accessibility mode is turned off. 这个想法是在打开辅助功能模式时向会话添加属性,并在关闭辅助功能模式时将其删除。

Those actions return a redirection the current page so the user immedially sees the interface changing from one mode to the other. 这些操作返回当前页面的重定向,因此用户可以立即看到界面从一种模式变为另一种模式。

When the accessibility is turned on, the view path is changed to append a /ac , because all my accessible views have the same file name that the non-accessibility ones, but in a subdirectory named ac . 启用辅助功能后,视图路径将更改为附加/ac ,因为我的所有可访问视图都具有与不可访问视图相同的文件名,但位于名为ac的子目录中。

@ManagedBean
@RequestScoped
public class AccessibilityMB {
    private boolean accessibilityOn = false;

    @PostConstruct
    public void init() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpSession session = (HttpSession)context.getExternalContext().getSession(false);
        if(session!=null) {
            Boolean accessibilityMode = (Boolean)session.getAttribute("AccessibilityMode");
            accessibilityOn = accessibilityMode!=null && accessibilityMode;
        }
    }

    public String turnAccessibilityOff() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpSession session = (HttpSession)context.getExternalContext().getSession(false);
        if(session!=null) {
            session.setAttribute("AccessibilityMode", accessibilityOn = true);
        }
        String viewId = context.getViewRoot().getViewId();
        return viewId+"?faces-redirect=true";
    }

    public String turnAccessibilityOn() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpSession session = (HttpSession)context.getExternalContext().getSession(false);
        if(session!=null) {
            accessibilityOn = false;
            session.removeAttribute("AccessibilityMode");
        }
        String viewId = context.getViewRoot().getViewId();
        int index = viewId.lastIndexOf("/ac/");
        if(index>-1)
            viewId = viewId.substring(0, index)+viewId.substring(index+3);
        return viewId+"?faces-redirect=true";
    }

    public boolean getAccessibilityOn() {
        return accessibilityOn;
    }
}

2. A PhaseListener to correct the path the views when accessibility mode is on 2.一个PhaseListener,用于在启用辅助功能模式时更正视图的路径

The PhaseListener just checks for the accessibility mode and, in such a circunstance, rewrites the path the view to look for in the ac subdirectoty. PhaseListener只检查辅助功能模式,并在这种情况下,重写在ac子目录中查找的视图的路径。 If the desided view exists there, the current component tree is discarded and rebuilt from the accessible version of the same view. 如果存在desided视图,则丢弃当前组件树并从同一视图的可访问版本重建。

Here the solution is not so good, because JSF already worked to build a component tree and I'm simply discarding it to reworking it from another file. 这里的解决方案并不是那么好,因为JSF已经在构建一个组件树,而我只是放弃它来从另一个文件重新编写它。

public class AccessibilityPhaseListener implements PhaseListener{
    private static final long serialVersionUID = 1L;

    @Override
    public void beforePhase(PhaseEvent event) {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpSession session = (HttpSession)context.getExternalContext().getSession(false);
        if(session==null) {
            return;
        }
        Boolean acessibilityMode = (Boolean)session.getAttribute("AcessibilityMode");
        if(acessibilityMode==null || !acessibilityMode)
            return;

        String viewId = context.getViewRoot().getViewId();
        if(acessibilityMode) {
            int index = viewId.lastIndexOf("/");
            viewId = viewId.substring(0, index+1)+"ac/"+viewId.substring(index+1);
        } else {
            int index = viewId.lastIndexOf("/");
            if(viewId.substring(index-3, index).equals("/ac"))
                viewId = viewId.substring(0, index-3)+viewId.substring(index);
        }

        URL url = null;
        try {
            url = context.getExternalContext().getResource(viewId);
        } catch (MalformedURLException e) {
        }

        if(url==null)
            return;
        ViewHandler handler = context.getApplication().getViewHandler();
        UIViewRoot root = handler.createView(context, viewId);

        root.setViewId(viewId);
        context.setViewRoot(root);
    }

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.RENDER_RESPONSE;
    }
}

Conclusion 结论

I could satisfy all my requirements: 我可以满足我的所有要求:

  1. No Java code had to be refactored and the application now works in two different modes; 没有Java代码必须重构,应用程序现在可以在两种不同的模式下工作;
  2. I rebuilt only the views I wanted, in cases where the original view works fine with the screen reader it was kept as it is; 我只重建了我想要的视图,如果原始视图与屏幕阅读器工作正常,它保持不变;
  3. The accessibility mode can be turned on and off at any time and the user has immediate response to such an action; 可以随时打开和关闭辅助功能模式,用户可以立即响应此类操作;

I undestand that this solution works with any kind of application modes, not only accessibility. 我不认为这个解决方案适用于任何类型的应用程序模式,而不仅仅是可访问性。 Any time someone needs to select a certain view instead of the other based on an application or session parameter, it will work. 任何时候有人需要根据应用程序或会话参数选择某个视图而不是另一个视图,它将起作用。 For instance, a multiculture application where the culture customization goes futher than color and language, requiring a complete redesign of views can take advantage of this model. 例如,多文化应用程序,其中文化定制比颜色和语言更进一步,需要完全重新设计视图可以利用此模型。

The downside of all this is the fact that, when the accessibility mode is on and there is an accessible version of a certain view, JSF will work twice, one time to build the original view and a second time to build the accessible version. 所有这些的缺点是,当可访问性模式打开并且存在特定视图的可访问版本时,JSF将工作两次,一次构建原始视图,第二次构建可访问版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM