Получить фрагмент (хэш) из URL и вставить значения в bean-компонент - PullRequest
16 голосов
/ 13 августа 2010

Я ищу способ ввести значения из фрагмента (#) 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)

Я хотел бы определить здесь мою ситуацию, и если у кого-то есть идея, я хотел бы попробовать их.

Я использую
RichFaces: 3.3.3,
Весна: 3.0.2. ВЫПУСК,
Hibernate: 3.5.3-Final,
JSF: 2.0.2-FCS,
PrettyFaces: 3.0.1

Веб-приложение генерирует следующий вид URL, где параметры перечислены после хеша (#). Идея состоит в том, чтобы иметь AJAX на основе Закладка URL. Поэтому каждый раз, когда я нажимаю на элемент, который меняет состояние системы, значение отправляется на сервер через AJAX и URL после хэша перезаписывается. Может быть от 1 до 3 параметров после хеш, количество параметров необязательное.

Моя цель состоит в том, чтобы, когда пользователь добавляет в закладки URL-адрес (с помощью хэша), а затем пересматривает сохраненную страницу, страница должна ввести правильные значения в систему и визуализировать страницу в предыдущем состоянии (как запрос-параметр).

Ниже у меня есть регулярное выражение, которое перехватывает все параметры после хеша.

//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})

Я знаю, что есть веб-сайты, которые как-то отправляют фрагмент URL в свою логическую часть на стороне сервера,

В любом случае, можно ли вводить значения из фрагментов URL в компоненты на стороне сервера?

Ответы [ 5 ]

8 голосов
/ 13 августа 2010

Вы можете сделать это с помощью window.onhashchange, который заполняет поле ввода скрытой формы, которая подает себя асинхронно, когда поле ввода изменилось.

Вот начальный примерстраница 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>

Вот как выглядит соответствующий компонент:

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;
    }

}

Вот и все.

Обратите внимание, что событие onhashchange является относительно новым ине поддерживается старыми браузерами.При отсутствии поддержки браузера (неопределенной и т. Д.) Вы бы хотели проверять window.location.hash с интервалами, используя вместо этого setInterval().Приведенный выше пример кода должен по крайней мере дать хороший старт.Работает как минимум на FF3.6 и IE8.

3 голосов
/ 13 августа 2010

Вот наиболее надежный способ извлечения фрагмента из синтаксически действительного URL / URI.

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

Как вы внедрите это в бин, будет зависеть от того, какую серверную среду вы используете, иВы делаете инъекцию, используя XML или аннотации, или делаете это программно.

1 голос
/ 13 августа 2010

Смотрите этот вопрос и особенно ответы: JSP Servlet anchor

  • Фрагмент не виден на на стороне сервера.
  • Вы можете извлечь фрагмент на стороне клиента, преобразовать его и отправить сервер через Ajax.
1 голос
/ 13 августа 2010

Фрагмент не виден со стороны сервера, доступ к нему возможен только через скрипты на стороне клиента.Обычно это делается так, что на стороне сервера генерируется не параметризованная страница, которая затем модифицируется скриптами в соответствии с параметрами фрагмента.Сценарии могут выполнять запросы AJAX с параметрами запроса, при этом ответы AJAX генерируются JSF с использованием bean-компонентов, управляемых параметрами.

Если вы абсолютно хотите, чтобы на стороне сервера был доступ к параметрам фрагмента при отображении страницысама, вам нужно перезагрузить страницу с параметрами вместо параметров запроса.

РЕДАКТИРОВАТЬ: Чтобы перезагрузить страницу, вы можете использовать этот код:

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;
}
0 голосов
/ 20 августа 2010

Большое спасибо за ваши идеи и особенно BalusC (большое спасибо вам). Моим окончательным решением была небольшая мутация, и я хотел бы поделиться со всеми вами.

Поскольку я использую richfaces 3.3.3, это похоже на использование jsf1.2, следовательно, нет <f:ajax>

В обычной ситуации вы должны щелкнуть ссылку со ссылкой, указывающей на внутреннюю ссылку <a id='internalLink'href='#internalLink'>. Я использую много предварительно упакованных компонентов, где не каждый кликабельный элемент является ссылкой <a>. Это может быть любой элемент HTML. Было очень полезно использовать плагин Bookmarkable jQuery Бена Алмана (http://benalman.com/projects/jquery-bbq-plugin/)

Обратите внимание: ниже, я могу программно установить значение фрагмента как ключ / значение, и в следующем коде я заменяю старое значение новым значением jQuery.bbq.pushState(state,2) (или я мог бы просто добавить за старое значение jQuery.bbq.pushState(state)).

В моем случае 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>

В richfaces это классный способ вызова методов установки из браузера с параметром. Обратите внимание, что sendURLFragment рассматривается как метод JS с 5 параметрами, а значения передаются на сервер (что очень здорово).

<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>

Делайте это, когда копируете и вставляете новый 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);
}   };  
...