Pass HTTP GET parameter to a JSF bean method - jsf

i want to pass GET parameter from URL to a method, that called by clicking on button.
For example i have URL: /someurl/semepage.xhtml?id=1. And i have a button on my page:
<p:commandButton value="say it" action="#{test.sayIt(param['id'])}"/>
The bean looks like:
#ManagedBean
#ViewScoped
public class Test{
public void sayIt(String value){
System.out.println(value);
}
}
But when i am clicking on button, its just not react. Why is this happen ? Method even not called.
If i pass arguments staticaly like here:
<p:commandButton value="say it" action="#{test.sayIt('someword')}"/>
everything is ok.

Here is one way - using the <f:param, like this:
<h:commandButton value="Test The Magic Word" action="#{test.sayIt}">
<f:param name="id" value="#{param['id']}"></f:param>
<f:ajax execute="something" render="something_else"></f:ajax>
</h:commandButton>
And in your bean
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext()
.getRequest();
String id = request.getParameter("id");

#Daniel's response is OK, but here it goes a simpler JSF 2-ish alternative for your case, using <f:viewParam /> and EL parameter passing. Note the <f:ajax /> is not needed in this case, as <p:commandButton /> has ajax behaviour by default.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head />
<h:body>
<f:metadata>
<f:viewParam name="id" />
</f:metadata>
<h:form>
<p:commandButton value="say it" action="#{bean.sayIt(id)}" />
</h:form>
</h:body>
</html>
#ManagedBean
#ViewScoped
public class Bean implements Serializable {
public void sayIt(String value) {
System.out.println(value);
}
}
Tested with JSF 2.2.5 and Primefaces 4. Remember changing tag namespaces in case of using JSF 2.1.x.

Just for the fun of it, have you tried request.getParameter('id')?

Related

Get validation failure reason for JSF [duplicate]

I have a problem with the h:messages tag in JSF that simply does not show any messages. In the Glassfish log are no errors when I click the button.
The setup is as follows:
test.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:j="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</h:head>
<h:body>
<h:messages globalOnly="true"/>
<h:form id="loginform">
<p:commandButton id="testButton" value="Test"
action="#{loginSessionBean.test()}" />
</h:form>
</h:body>
</html>
With The SessionScopedBean:
#ManagedBean
#SessionScoped
public class LoginSessionBean implements Serializable {
private static final long serialVersionUID = 1L;
...
public String test(){
FacesContext fc = FacesContext.getCurrentInstance();
fc.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, "Test!", null));
return "";
}
You're sending an ajax request with PrimeFaces <p:commandButton>. Ajax requests have by default no form of feedback (unless PrimeFaces' autoUpdate="true" is been used somewhere). You should be explicitly specifying parts of the view which you'd like to update on ajax response.
One way is specifying the update attribute on <p:commandButton> to point to the client ID of the <h:messages> component.
<h:messages id="messages" ... />
<h:form>
<p:commandButton ... update=":messages" />
</h:form>
Another way is to replace it by PrimeFaces <p:messages> which has an autoUpdate attribute for the purpose of automatic update on ajax response.
<p:messages ... autoUpdate="true" />
<h:form>
<p:commandButton ... />
</h:form>
A completely different alternative is to turn off ajax by adding ajax="false" attribute to the button, this way a synchronous postback will be performed which effectively results in a full page update, exactly like as how the standard JSF <h:commandButton> behaves when used without <f:ajax>.
<h:messages ... />
<h:form>
<p:commandButton ... ajax="false" />
</h:form>
See also:
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes

JSF CommandButtons's action is not called when using rendered

When viewing this page with ?mode=test, the button doesn't work. It loads this page without ?mode=test, but h:panelGroup is rendered (because mode is set somewhere else). I use two methods of sending mode (h:inputHidden f:param) and to the server and nothing helps. View scoped bean is not available in CDI. What is the possible solution to this?
XHTML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:view>
<f:metadata>
<f:viewParam name="mode" value="#{test.mode}" />
</f:metadata>
<h:panelGroup layout="block" rendered="#{test.mode.equals('test')}">
<h:form>
<h:inputHidden value="#{test.mode}" />
<h:commandButton value="Run a method" action="#{test.method}">
<f:param name="mode" value="#{test.mode}" />
</h:commandButton>
</h:form>
</h:panelGroup>
<h:messages />
</f:view>
</html>
Java
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
#Named("test")
#RequestScoped
public class TestBean {
private String mode;
public void method() {
System.out.print(mode);
}
public String getMode() {
return mode;
}
public void setMode(String mode) {
this.mode = mode;
}
}
You've got a wide range of possibilities. The easiest one for you is not to bind the view parameter to the backing bean, just keep it bound to the view:
test.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:view>
<f:metadata>
<f:viewParam name="mode" value="#{mode}" />
</f:metadata>
<h:form rendered="#{mode eq 'test'}">
<h:commandButton value="Run a method" action="#{test.method(mode)}" />
</h:form>
<h:messages />
</f:view>
</html>
Test.java
#Named
#RequestScoped
public class Test {
public void method(String mode) {
System.out.print(mode);
}
}
If you however would like to switch to #ViewScoped, CDI compatible annotation is now available in JSF 2.2 version. The namespaces you're using suggest you do use that version, so go with it. For JSF prior versions, there's also the chance to do it with custom Omnifaces' annotation.
See also:
Omnifaces #ViewScoped annotation
#ViewScoped in CDI with JSF 2.2
Differences between EL 2.1 and 2.2

How to redirect to same page with all parameters?

In my app I have JSF page with some parameters
(url of example page: /pages/user.xhtml?id=123&userToShowId=2)
On this page i have a commandButton. After click it I want to redirect to the same page with all parameters. I know, that for this specified page I can do this manually this way:
public String redirect(){
//extCtx - ExternalContext
//ctx - FacesContext
Map<String,String> param = extCtx.getRequestParameterMap();
String currentURL = ctx.getViewRoot().getViewId();
return currentURL+"?userToShowId="+param.get("userToShowId")+"&id="+param.get("id");
}
But what to do when I want to get universal way to redirect from any page with any parameters?
If I have view parameters only at pages, without set it as a bean property:
<f:metadata>
<f:viewParam name="backurl"/>
<f:viewParam name="id"/>
</f:metadata>
not with value:
<f:metadata>
<f:viewParam name="backurl" value=#{bean.id}/>
<f:viewParam name="id" value=#{bean.id}/>
</f:metadata>
can I use includeViewParams=true to do my work?
You can do it without having to bind them to the managed bean. In JSF there are two main navigation cases:
Perform a view request without doing nothing more. That's an HTTP GET request and is done using h:button, which doesn't need to be wrapped by a form and acts like a link.
Perform a form POST and after that ask for another page (REDIRECT-GET), that's done by h:commandButton.
You can include view params in both cases. That's how it's done:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core">
<h:head />
<h:body>
<f:metadata>
<f:viewParam name="backurl" />
<f:viewParam name="id" />
</f:metadata>
<h:outputText value="backurl value is #{backurl} and id value is #{id}" />
<br />
<h:button outcome="index" value="redirect">
<f:param name="backurl" value="directUrl" />
<f:param name="id" value="directId" />
</h:button>
<h:form>
<h:commandButton value="action" action="#{bean.redirect}" />
</h:form>
</h:body>
</html>
#ManagedBean
#RequestScoped
// You could also use #ViewScoped
public class Bean implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Performs a redirection to index destination view with the given params
*
* #return
*/
public String redirect() {
return "index?backurl=actionUrl&id=actionId&faces-redirect=true";
}
}
You'll see when you initially load the page, both backurl and id don't have a value.
The first button performs a GET request with fixed view parameter values. When view loads again, values are already there. Second button does the same but using an action method.
Keep in mind that using #RequestScoped or #ViewScoped here has the same effect, as #RequestScoped doesn't maintain the state of the bean and #ViewScoped destroys it each time an String value is returned from the method, which is happening every time we invoke it.
Try this :
return currentURL + "?faces-redirect=true&includeViewParams=true";

view parameters in session scoped bean

I have some problems with session scoped bean working with f:viewParam. So I have two pages, test_first.xhtml and test_second.xhtml, and a TestBean.java.
first.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head/>
<h:body>
<h:form>
<h:link value="link1" outcome="test_second" >
<f:param name="id" value="1"/>
</h:link>
<br/><br/>
<h:link value="link2" outcome="test_second" >
<f:param name="id" value="2"/>
</h:link>
</h:form>
</h:body>
</html>
second.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<f:metadata>
<f:viewParam name="id" value="#{testBean.userId}" />
</f:metadata>
<h:head/>
<h:body>
<h:form>
This is the second page.
<h:outputText value="Selected id is #{testBean.userId}" />
<h:commandButton value="Print page id" action="#{testBean.print()}" />
<h:commandButton styleClass="submitButton" value="Submit" action="#{testBean.submit}">
<f:ajax execute="#form" render="#form"/>
</h:commandButton>
</h:form>
</h:body>
</html>
TestBean.java:
#ManagedBean
#SessionScoped
public class TestBean implements Serializable{
private Integer userId;
public void print() {
System.out.println(userId);
}
public void submit() {
System.out.println(userId);
}
/...
}
Start running from first.xhtml, if I open link1 in a new tab and then open link2 in another new tab. Now I got two pages.
If I click the "Print page id" button in link1, 1 will be printed in the console. In link2 the printed value will be 2.
But if I click the Submit button in link1, 2 will be printed and the rendered text will change from 1 to 2. (because link2 is opened later and the bean is session scoped?)
(Update: Why is this case? How can I still print "1" if I click "Submit"?)
I want to keep the bean as session scoped for other properties basically. So any thoughts on this or any alternative methods? Many thanks!
If you want it working in different tabs or windows, you need to put those tab specific properties on a ViewScoped or RequestScoped Bean. For properties that are session specific, you could create another Bean and make it SessionScoped.

#Inject to pass params to a CDI #Named bean via URL

If I cannot use the #ManagedProperty annotation with #Named, because #ManagedProperty doesn't work in CDI(?), then how do you pass params in the URL to the facelets client? In my code, I want to pass javax.mail.getMessageNumber() to details.xhtml through the "back" and "forward" buttons.
I understand that #Inject should be used, but what is being injected and how, please?
From the glassfish logs, id is always 0, which is quite odd. Even when "forward" is clicked, id never gets above 1 no matter how many times the button is clicked. Of course, that's merely a symptom of the problem. The desired output, of course, is to advance to the next Message.
Perhaps put the Message, or at least the int, into the session?
The client as so:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="./template.xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core">
<ui:define name="top">
<h:form>
<h:form>
<h:outputLink id="link1" value="detail.xhtml">
<f:param name="id" value="#{detail.back()}" />
<h:outputText value="back" />
</h:outputLink>
</h:form>
</h:form>
<h:form>
<h:outputLink id="link1" value="detail.xhtml">
<f:param name="id" value="#{detail.forward()}" />
<h:outputText value="forward" />
</h:outputLink>
</h:form>
</ui:define>
<ui:define name="content">
<h:outputText value="#{detail.content}"></h:outputText>
</ui:define>
</ui:composition>
and the bean as so:
package net.bounceme.dur.nntp;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.RequestScoped;
import javax.faces.bean.ManagedProperty;
import javax.inject.Named;
import javax.mail.Message;
#Named
#RequestScoped
public class Detail {
private static final Logger logger = Logger.getLogger(Detail.class.getName());
private static final Level level = Level.INFO;
#ManagedProperty(value = "#{param.id}")
private Integer id = 0;
private Message message = null;
private SingletonNNTP nntp = SingletonNNTP.INSTANCE;
public Detail() {
message = nntp.getMessage(id);
}
public int forward() {
logger.log(level, "Detail.forward.." + id);
id = id + 1;
logger.log(level, "..Detail.forward " + id);
return id;
}
public int back() {
logger.log(level, "Detail.back.." + id);
id = id - 1;
logger.log(level, "..Detail.back " + id);
return id;
}
public Message getMessage() {
return message;
}
public String getContent() throws Exception {
return message.getContent().toString();
}
}
This works only with the in JSF 2.3 introduced javax.faces.annotation.ManagedProperty.
#Inject #ManagedProperty("#{param.id}")
private String id;
The now deprecated javax.faces.bean.ManagedProperty annotation works only in JSF #ManagedBean classes. I.e. in instances which are managed by JSF. It does not work in instances which are managed by CDI #Named. Further, you've made another mistake: you're trying to prepare the Message based on the managed property in the constructor. If it were a real #ManagedBean, that would also not have worked. The managed property is not available during construction, simply because it's not possible to call the setter method before the constructor is called. You should have used a #PostConstruct method for this.
If you cannot upgrade to JSF 2.3, you'd need to create a custom CDI annotation. A concrete example is posted in this blog. Here's an extract of relevance:
The custom #HttpParam annotation:
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface HttpParam {
#NonBinding
public String value() default "";
}
The annotation value producer:
public class HttpParamProducer {
#Inject
FacesContext facesContext;
#Produces
#HttpParam
String getHttpParameter(InjectionPoint ip) {
String name = ip.getAnnotated().getAnnotation(HttpParam.class).value();
if ("".equals(name)) name = ip.getMember().getName();
return facesContext.getExternalContext()
.getRequestParameterMap()
.get(name);
}
}
An usage example:
#Inject #HttpParam
private String id;
JSF utility library OmniFaces has a #Param for exactly this purpose, with builtin support for JSF conversion and validation.
Alternatively, you can also manually grab the request parameter from the external context in the Detail managed bean. The recommended way to do managed bean initialization is to use a #PostConstruct method, not the constructor, as the constructor could be used for completely different purposes than managed bean creation:
#PostConstruct
public void init() {
String id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
// ...
}
Another way, IMO also more suitable for this particular case, is to use <f:viewParam> which also allows you to convert the ID to Message directly by a custom converter.
<f:metadata>
<f:viewParam name="id" value="#{detail.message}" converter="messageConverter" />
</f:metadata>
with just
#Named
public class Detail {
private Message message;
// Getter+setter
}
and a
#FacesConverter("messageConverter")
public class MessageConverter implements Converter {
// Convert string id to Message object in getAsObject().
// Convert Message object to string id in getAsString().
}
See also
ViewParam vs #ManagedProperty(value = "#{param.id}")
Communication in JSF 2.0 - processing GET request parameters
First, to explain the alien part - Glassfish uses JBoss Weld as its CDI implementation, Oracle does not develop an implementation of its own.
And concerning the meaning of the error message: FacesContext is simply not injectable via #Inject. There is an rather old feature request for that, and I think Seam or Solder provide a producer. But there's no need to integrate either of the libraries just for that. Access faces context like you would in normal managed bean, via FacesContext.getCurrentInstance().
I was asking a complex way of doing a simple thing. In CDI, to pass params around you cannot use #ManagedProperty, as explained above by BalusC. Instead, you just setup your xhtml files as so:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="./template.xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core">
<ui:define name="top">
<h:form>
<h:commandButton action="#{messages.back()}" value="..back" />
</h:form>
<h:form>
<h:commandButton action="#{messages.forward()}" value="forward.." />
</h:form>
</ui:define>
<ui:define name="content">
<h:dataTable value="#{messages.model}" var="m">
<h:column>
<f:facet name="id">
<h:outputText value="id" />
</f:facet>
<h:outputLink id="hmmm" value="detail.xhtml">
<f:param name="id" value="#{m.getMessageNumber()}" />
<h:outputText value="#{m.getMessageNumber()}" />
</h:outputLink>
</h:column>
<h:column>
<f:facet name="subject">
<h:outputText value="subject" />
</f:facet>
<h:outputText value="#{m.subject}"></h:outputText>
</h:column>
<h:column>
<f:facet name="content">
<h:outputText value="content" />
</f:facet>
<h:outputText value="#{m.sentDate}"></h:outputText>
</h:column>
<h:column>
<f:facet name="date">
<h:outputText value="date" />
</f:facet>
<h:outputLink value="#{messages.getUrl(m)}">#{messages.getUrl(m)}</h:outputLink>
</h:column>
</h:dataTable>
</ui:define>
</ui:composition>
to:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="./template.xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core">
<ui:define name="top">
<h:form>
<h:outputLink id="back" value="detail.xhtml">
<f:metadata>
<f:viewParam name="id" value="#{detail.id}" />
</f:metadata>
<f:param name="id" value="#{detail.back()}" />
<h:outputText value="back" />
</h:outputLink>
</h:form>
<h:form>
<h:outputLink id="forward" value="detail.xhtml">
<f:metadata>
<f:viewParam name="id" value="#{detail.id}" />
</f:metadata>
<f:param name="id" value="#{detail.forward()}" />
<h:outputText value="forward" />
</h:outputLink>
</h:form>
</ui:define>
<ui:define name="content">
<h:outputText value="#{detail.content}"></h:outputText>
</ui:define>
</ui:composition>
I'm only including this for anyone who comes along, to clarify that, for this simple example, you don't need a Converter, that the default works fine.
The original question is more than a bit mangled, as well. From looking at other questions on this, I think others could benefit from a simple example such as this. So many examples are overly complex, or involve EJB, etc.

Resources