我正在寻找一种方法,将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.RELEASE,
休眠:3.5.3-决赛,
JSF:2.0.2-FCS,
PrettyFaces:3.0.1
Web应用程序生成以下类型的URL参数 列在哈希(#)之后。这个想法是基于ajax 可加标签的网址。所以每次我点击一个改变了的元素 在系统状态下,该值通过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片段中的值注入服务器端bean吗?
答案 0 :(得分:8)
您可以在window.onhashchange
的帮助下执行此操作,该window.location.hash
填充隐藏表单的输入字段,该字段在输入字段更改时异步提交。
以下是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>
以下是适当的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;
}
}
就是这样。
请注意,onhashchange
事件相对较新,旧浏览器不支持。如果没有浏览器支持(未完成等等),您可以使用setInterval()
定期检查{{3}}。上面的代码示例至少应该给出良好的启动。它至少适用于FF3.6和IE8。
答案 1 :(得分:3)
这是从语法上有效的URL / URI中提取片段的最可靠方法。
URI uri = new URI(someString);
String fragment = uri.getFragment();
如何将其注入bean将取决于您使用的服务器端框架,以及您是使用XML或注释进行注入,还是以编程方式进行注入。
答案 2 :(得分:1)
无法从服务器端看到该片段,只能通过客户端脚本访问它。通常做的方式是服务器端生成非参数化页面,然后根据片段参数由脚本修改。脚本可以使用查询参数发出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;
}
答案 3 :(得分:1)
观看此问题,特别是答案:JSP Servlet anchor
答案 4 :(得分:0)
非常感谢你的想法&amp;特别是BalusC(给你很多荣誉)。我的最终解决方案是轻微的变异,我想与大家分享。
由于我使用的是richfaces 3.3.3,它就像使用jsf1.2,因此没有<f:ajax>
在传统情况下,您需要点击指向内部链接<a id='internalLink'href='#internalLink'>
的href链接。我正在使用许多预先打包的组件,而不是每个可点击的项目都是链接<a>
。它可以是任何html元素。使用Ben Alman的Bookmarkable jQuery插件(http://benalman.com/projects/jquery-bbq-plugin/)
下面请注意,onclick我可以通过编程方式将片段的值设置为键/值,在下面的代码中,我用新值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中,这是一种使用参数从浏览器调用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>
当您复制粘贴新网址并加载页面时,请执行此操作。
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);
} };