Redirect 如何重定向到JSF中的锚?

Redirect 如何重定向到JSF中的锚?,redirect,jsf-2,accessibility,anchor,Redirect,Jsf 2,Accessibility,Anchor,假设我在JSF管理的Bean中有这样一个操作: public String doSomething() { FacesContext.getCurrentInstance().getExternalContext().getFlash().put("msg", "Something was done successfully"); return "view?faces-redirect=true"; } 我的视图有一个id为msg的锚元素。我希望url具有此锚(用于可访问性问题

假设我在JSF管理的Bean中有这样一个操作:

public String doSomething() {
    FacesContext.getCurrentInstance().getExternalContext().getFlash().put("msg", "Something was done successfully");
    return "view?faces-redirect=true";
}
我的
视图
有一个id为
msg
的锚元素。我希望url具有此锚(用于可访问性问题),如:

或者我的FacesServlet过滤模式

返回“view#msg?faces redirect=true”
显然不起作用,因为JSF(至少是mojarra)会尝试将
view#msg
作为一个视图进行评估

因此,我的问题是如何使JSF最终重定向到带有
#msg
的URL

因为JSF(至少是mojarra)会尝试将
view#msg
作为一个视图进行评估

哦,真讨厌。这绝对值得JSF/Mojarra boys提出一个增强请求

最好是在的帮助下手动发送重定向

(假设
FacesServlet
映射到
*.xhtml

或者,您可以有条件地呈现一段JS,而这段JS会执行此操作


window.location.hash='msg';

您试图构建一个非法URL-片段(
#
)始终是URL的最后一部分

return“view?faces redirect=true#msg”
将是正确的URL

不幸的是,至少在JSF2.2中,默认的
NavigationHandler
剥离了该片段

虽然这两种选择也很有效,但我还有第三种选择。用小补丁包住
NavigationHandler
ViewHandler

public class MyViewHandler extends ViewHandlerWrapper {

    public static final String REDIRECT_FRAGMENT_ATTRIBUTE = MyViewHandler.class.getSimpleName() + ".redirect.fragment";

    // ... Constructor and getter snipped ...

    public String getRedirectURL(final FacesContext context, final String viewId, final Map<String, List<String>> parameters, final boolean includeViewParams) {
        final String redirectURL = super.getRedirectURL(context, viewId, removeNulls(parameters), includeViewParams);
        final Object fragment = context.getAttributes().get(REDIRECT_FRAGMENT_ATTRIBUTE);
        return fragment == null ? redirectURL : redirectURL + fragment;
    }

}

public class MyNavigationHandler extends ConfigurableNavigationHandlerWrapper {

    // ... Constructor and getter snipped ...

    public void handleNavigation(final FacesContext context, final String fromAction, final String outcome) {
        super.handleNavigation(context, fromAction, 
            storeFragment(context, outcome));
    }

    public void handleNavigation(final FacesContext context, final String fromAction, final String outcome, final String toFlowDocumentId) {
        super.handleNavigation(context, fromAction, 
            storeFragment(context, outcome), toFlowDocumentId);
    }

    private static String storeFragment(final FacesContext context, final String outcome) {
        if (outcome != null) {
            final int hash = outcome.lastIndexOf('#');
            if (hash >= 0 && hash + 1 < outcome.length() && outcome.charAt(hash + 1) != '{') {
                context.getAttributes().put(MyViewHandler.REDIRECT_FRAGMENT_ATTRIBUTE, outcome.substring(hash));
                return outcome.substring(0, hash);
            }
        }
        return outcome;
    }
}
公共类MyViewHandler扩展了ViewHandlerWrapper{
公共静态最终字符串重定向\u片段\u属性=MyViewHandler.class.getSimpleName()+“.REDIRECT.FRAGMENT”;
//…构造函数和getter被截断了。。。
公共字符串getRedirectURL(最终FacesContext上下文、最终字符串viewId、最终映射参数、最终布尔includeViewParams){
最终字符串redirectURL=super.getRedirectURL(上下文、视图ID、removeNulls(参数)、includeViewParams);
最终对象片段=context.getAttributes().get(重定向\u片段\u属性);
return fragment==null?redirectURL:redirectURL+fragment;
}
}
公共类MyNavigationHandler扩展ConfigurableNavigationHandlerWrapper{
//…构造函数和getter被截断了。。。
public void handleNavigation(最终面上下文上下文、操作的最终字符串、最终字符串结果){
超级掌上导航(上下文、fromAction、,
存储片段(上下文、结果);
}
public void handleNavigation(最终面上下文上下文、最终字符串fromAction、最终字符串output、最终字符串toFlowDocumentId){
超级掌上导航(上下文、fromAction、,
storeFragment(上下文、结果),toFlowDocumentId);
}
私有静态字符串storeFragment(最终FacesContext上下文,最终字符串结果){
如果(结果!=null){
final int hash=output.lastIndexOf('#');
if(hash>=0&&hash+1

(由于JAVASERVERFACES-3154的修复,我不得不为ViewHandler创建包装)

这段JS考虑得不错。另外,
ExternalContext#redirect()
非常有效。再一次,一个很好的答案:)我想补充一点,如果你想跳转到同一页面上的锚,重定向重新加载,所以JS是更好的选择。别忘了把代码放在你想跳转到的元素后面。
public void doSomething() throws IOException {
    ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
    ec.getFlash().put("msg", "Something was done successfully");
    ec.redirect("view.xhtml#msg");
}
public class MyViewHandler extends ViewHandlerWrapper {

    public static final String REDIRECT_FRAGMENT_ATTRIBUTE = MyViewHandler.class.getSimpleName() + ".redirect.fragment";

    // ... Constructor and getter snipped ...

    public String getRedirectURL(final FacesContext context, final String viewId, final Map<String, List<String>> parameters, final boolean includeViewParams) {
        final String redirectURL = super.getRedirectURL(context, viewId, removeNulls(parameters), includeViewParams);
        final Object fragment = context.getAttributes().get(REDIRECT_FRAGMENT_ATTRIBUTE);
        return fragment == null ? redirectURL : redirectURL + fragment;
    }

}

public class MyNavigationHandler extends ConfigurableNavigationHandlerWrapper {

    // ... Constructor and getter snipped ...

    public void handleNavigation(final FacesContext context, final String fromAction, final String outcome) {
        super.handleNavigation(context, fromAction, 
            storeFragment(context, outcome));
    }

    public void handleNavigation(final FacesContext context, final String fromAction, final String outcome, final String toFlowDocumentId) {
        super.handleNavigation(context, fromAction, 
            storeFragment(context, outcome), toFlowDocumentId);
    }

    private static String storeFragment(final FacesContext context, final String outcome) {
        if (outcome != null) {
            final int hash = outcome.lastIndexOf('#');
            if (hash >= 0 && hash + 1 < outcome.length() && outcome.charAt(hash + 1) != '{') {
                context.getAttributes().put(MyViewHandler.REDIRECT_FRAGMENT_ATTRIBUTE, outcome.substring(hash));
                return outcome.substring(0, hash);
            }
        }
        return outcome;
    }
}