javascript 从 URL 检索片段(哈希)并将值注入 bean

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3475076/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 01:17:14  来源:igfitidea点击:

Retrieve the fragment (hash) from a URL and inject the values into the bean

javajavascriptjsffaceletsfragment-identifier

提问by Choesang

I am looking for a way to inject values from the fragment (#) of a URL into bean(JSF), in the same way query-parameter values are injected. I am using Ben Alman's Bookmarkable jQuery plugin (http://benalman.com/projects/jquery-bbq-plugin/) to create the URL fragments. I was hoping that Custom regex patterns from prettyFaces could be a way to solve my problem but until now I have been unsuccessful.

我正在寻找一种将 URL 片段 (#) 中的值注入 bean(JSF) 的方法,与注入查询参数值的方式相同。我正在使用 Ben Alman 的 Bookmarkable jQuery 插件 ( http://benalman.com/projects/jquery-bbq-plugin/) 创建 URL 片段。我希望来自 PrettyFaces 的自定义正则表达式模式可以解决我的问题,但直到现在我都没有成功。

(http://ocpsoft.com/docs/prettyfaces/snapshot/en-US/html_single/#config.pathparams.regext)

http://ocpsoft.com/docs/prettyfaces/snapshot/en-US/html_single/#config.pathparams.regext

I would like to define here my situation and if any one has an idea, i would love to try them out.

我想在这里定义我的情况,如果有人有想法,我很想尝试一下。

I am using
RichFaces: 3.3.3,
Spring: 3.0.2.RELEASE,
Hibernate: 3.5.3-Final,
JSF: 2.0.2-FCS,
PrettyFaces: 3.0.1

我正在使用
RichFaces:3.3.3,
Spring:3.0.2.RELEASE,
Hibernate:3.5.3-Final,
JSF:2.0.2-FCS,
PrettyFaces:3.0.1

The web application generates, following kind of URL where parameters are listed after a hash(#). The idea is to have an ajax based Bookmarkable URL. So every time I click on an element that changes the state of the system, the value is sent to the server via ajax and the URL after the hash is rewritten. There can be 1 to 3 parameters after the hash, the number of parameters are optional.

Web 应用程序生成以下类型的 URL,其中参数列在哈希 (#) 之后。这个想法是有一个基于 ajax 的可书签 URL。所以每次我点击一个改变系统状态的元素时,值都会通过ajax发送到服务器,并在重写哈希后的URL。hash后可以有1到3个参数,参数个数可选。

My goal is, when the user bookmarks the URL (with hash) and than revisits the saved page, the page should inject the correct values into the system and visualize the page in the previous state (like query-parameter).

我的目标是,当用户为 URL(使用哈希)添加书签并重新访问保存的页面时,页面应该将正确的值注入系统并在先前状态下可视化页面(如查询参数)。

Below, I have a regular expression that would catch all the parameters after the hash.

下面,我有一个正则表达式,可以捕获散列后的所有参数。

//URL:   
http://localhost:8080/nymphaea/workspace/#node=b48dd073-145c-4eb6-9ae0-e1d8ba90303c&lod=75e63fcd-f94a-49f5-b0a7-69f34d4e63d7&ln=en

//Regular Expression:    
\#(\w*\=(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}))|\&(\w*\=(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}))|\&(\w*\=\w{2})

I know there are websites that some how send the URL fragment into there server side logic,

我知道有些网站如何将 URL 片段发送到服务器端逻辑中,

Is there anyway to inject values from the URL fragments into server side beans?

是否有将 URL 片段中的值注入服务器端 bean 的方法?

采纳答案by BalusC

You can do this with help of window.onhashchangewhich fills an input field of a hidden form which submits itself asynchronously when the input field has changed.

您可以借助window.onhashchangewhich 填充隐藏表单的输入字段来完成此操作,该表单在输入字段更改时异步提交自身。

Here's a kickoff example of the Facelets page:

这是 Facelets 页面的启动示例:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>SO question 3475076</title>
        <script>
            window.onload = window.onhashchange = function() {
                var fragment = document.getElementById("processFragment:fragment");
                fragment.value = window.location.hash;
                fragment.onchange();
            }
        </script>
        <style>.hide { display: none; }</style>
    </h:head>
    <h:body>
        <h:form id="processFragment" class="hide">
            <h:inputText id="fragment" value="#{bean.fragment}">
                <f:ajax event="change" execute="@form" listener="#{bean.processFragment}" render=":showFragment" />
            </h:inputText>
        </h:form>
        <p>Change the fragment in the URL. Either manually or by those links:
            <a href="#foo">foo</a>, <a href="#bar">bar</a>, <a href="#baz">baz</a>
        </p>
        <p>Fragment is currently: <h:outputText id="showFragment" value="#{bean.fragment}" /></p>
    </h:body>
</html>

Here's how the appropriate bean look like:

下面是合适的 bean 的样子:

package com.stackoverflow.q3475076;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.event.AjaxBehaviorEvent;

@ManagedBean
@RequestScoped
public class Bean {

    private String fragment;

    public void processFragment(AjaxBehaviorEvent event) {
        // Do your thing here. This example is just printing to stdout.
        System.out.println("Process fragment: " + fragment);
    }

    public String getFragment() {
        return fragment;
    }

    public void setFragment(String fragment) {
        this.fragment = fragment;
    }

}

That's all.

就这样。

Note that the onhashchangeevent is relatively new and not supported by the older browsers. In absence of the browser support (undefinied and so on), you'd like to check window.location.hashat intervals using setInterval()instead. The above code example should at least give a good kickoff. It works at at least FF3.6 and IE8.

请注意,该onhashchange事件相对较新,较旧的浏览器不支持。在没有浏览器支持(未定义等)的情况下,您希望window.location.hash每隔一段时间检查一次setInterval()。上面的代码示例至少应该提供一个很好的启动。它至少适用于 FF3.6 和 IE8。

回答by Stephen C

Here's the most reliable way to extract a fragment from a syntactically valid URL / URI.

这是从语法有效的 URL / URI 中提取片段的最可靠方法。

 URI uri = new URI(someString);
 String fragment = uri.getFragment();

How you inject this into a bean will depend on what server-side framework you are using, and whether you are doing the injection using XML or annotations, or doing it programmaticaly.

您如何将其注入 bean 将取决于您使用的服务器端框架,以及您是使用 XML 或注释进行注入,还是以编程方式进行注入。

回答by clacke

The fragment cannot be seen from the server-side, it can only be accessed by client-side scripts. The way it's usually done is that the server-side generates a non-parameterized page, which is then modified by scripts in accordance with the fragment parameters. The scripts could make AJAX requests with query parameters, where the AJAX responses are generated by JSF using beans controlled by the parameters.

该片段在服务器端是看不到的,它只能被客户端脚本访问。通常的做法是服务端生成一个非参数化的页面,然后根据片段参数由脚本修改。脚本可以使用查询参数发出 AJAX 请求,其中 AJAX 响应由 JSF 使用由参数控制的 bean 生成。

If you absolutely want the server-side to have access to the fragment parameters when rendering the page itself, you need to reload the page with the parameters as query parameters instead.

如果您绝对希望服务器端在呈现页面本身时访问片段参数,则需要使用参数作为查询参数重新加载页面。

EDIT: To reload the page you could use this code:

编辑:要重新加载页面,您可以使用以下代码:

if (window.location.hash != '') {
  var newsearch = window.location.search;
  if(newsearch != '') {
    newsearch += '&';
  }
  newsearch += window.location.hash.match(/#?(.*)/)[1];
  window.location.hash = '';
  window.location.search = newsearch;
}

回答by pcjuzer

Watch this question and especially the answers: JSP Servlet anchor

观看这个问题,尤其是答案:JSP Servlet anchor

  • Fragment cannot be seen on server-side.
  • You can extract fragment on client-side, convert it and send to the server via Ajax.
  • 在服务器端看不到片段。
  • 您可以在客户端提取片段,将其转换并通过 Ajax 发送到服务器。

回答by Choesang

Thank you very much for your ideas & specially BalusC (much kudos to you). My final solution was a slight mutation and i would like to share with you all.

非常感谢您的想法,特别是 BalusC(非常感谢您)。我的最终解决方案是一个轻微的变化,我想与大家分享。

Since I am using richfaces 3.3.3, it is like using jsf1.2, hence no <f:ajax>

由于我使用的是richfaces 3.3.3,就像使用jsf1.2一样,因此没有 <f:ajax>

In a conventional situation, you are expected to click on a link with a href pointing to an internal link <a id='internalLink'href='#internalLink'>. I am using many prepackaged components where not every clickable item is a link <a>. It can be any html element. It was very useful to use Ben Alman's Bookmarkable jQuery plugin (http://benalman.com/projects/jquery-bbq-plugin/)

在常规情况下,您应该单击带有指向内部链接的 href 的链接<a id='internalLink'href='#internalLink'>。我使用了许多预先打包的组件,其中并非每个可点击的项目都是一个链接<a>。它可以是任何 html 元素。使用 Ben Alman 的 Bookmarkable jQuery 插件(http://benalman.com/projects/jquery-bbq-plugin/)非常有用

Please note below that, onclick I can programmatically set the value of the fragment as key/value and in the following code I replace the old value with a new value jQuery.bbq.pushState(state,2)(or I could have simply added behind the old value jQuery.bbq.pushState(state)).

请注意下面的内容,onclick 我可以以编程方式将片段的值设置为键/值,在下面的代码中,我将旧值替换为新值jQuery.bbq.pushState(state,2)(或者我可以简单地添加到旧值后面jQuery.bbq.pushState(state))。

In my case, ws->md->ndis a hierarchical data where it is enough to have one of them and its parents are calculated on server, so i replace the parent value with child value.

在我的情况下,ws->md->nd是一个分层数据,其中有一个就足够了,它的父级在服务器上计算,所以我用子级值替换了父级值。

<ui:repeat value="#{workspaceController.modulesForWorkspace}" var="item">  
 <a4j:commandLink onclick="var state = {}; state['md'] = '#{item.uuid}';
  jQuery.bbq.pushState( state, 2 );"    
  action="#{workspaceController.setSelectedModule}"
  reRender="localesList" 
  oncomplete="selectNavigationElement(this.parentNode>
    <f:param name="selectedModule" value="#{item.uuid}"/>
  </a4j:commandLink>
</ui:repeat>

In richfaces, this is a cool way to call the setter methods from browser with a parameter. Note that sendURLFragmentis treated as a JS method with 5 parameters and the values are passed to the server (which is very cool).

在 Richfaces 中,这是使用参数从浏览器调用 setter 方法的一种很酷的方式。请注意,它sendURLFragment被视为具有 5 个参数的 JS 方法,并将值传递给服务器(这非常酷)。

<h:form id="processFragment" prependId="false" style="display: none">
  <h:inputText id="fragment" value="#{workspaceController.selectedWorkspace}">                                  
   <a4j:support event="onchange"/>
  </h:inputText>    
<a4j:jsFunction name="sendURLFragment" reRender="workspaces">
 <a4j:actionparam name="ws" assignTo="#{workspaceController.selectedWorkspace}"/>
 <a4j:actionparam name="md" assignTo="#{workspaceController.selectedModule}"/>
 <a4j:actionparam name="nd" assignTo="#{workspaceController.selectedContentNode}"/>
 <a4j:actionparam name="ld" assignTo="#{workspaceController.selectedLOD}"/>
 <a4j:actionparam name="ln" assignTo="#{workspaceController.contentNodeTreeLocale}"  
 converter="localeConverter"/>                              
</a4j:jsFunction>
</h:form>

Do the thing, when you copy-paste the new url and load the page.

做这件事,当你复制粘贴新的 url 并加载页面时。

window.onload = function(){
if(window.location.hash != ""){  
    //Parse the fragment (hash) from a URL, deserializing it into an object            
    var deparamObj = jQuery.deparam.fragment();
    var ws= '', md= '', nd= '', ld= '', ln = '';            
    jQuery.each(deparamObj, function(key, value) {              
        switch(key){
            case 'ws':
                ws = value;
                break;
            case 'md':
                md = value;
                break;
            case 'nd':
                nd = value;
                break;
            case 'ld':
                ld = value;
                break;
            case 'ln':
                ln = value;
                break;
            default:
                break;          
        }

    });
    sendURLFragment(ws,md,nd,ld,ln);
}   };