How to open JSF page using JAX-RS web service?

2019-07-18 09:29发布

问题:

I would like other web application (in .net or any other) to call my JAX-RS web service to set and open my JSF page with some passed values.

E.g.

  • Another web application just pass the userId and a token to open an entry page.
  • User will complete the entry and service will return the uniqueId for created entry.

I am confused in how I can set JSF context parameters and open that JSF page using JAX-RS. Can anyone give idea about how to set value of JSF session scoped managed bean using web service?

回答1:

First of all, this question indicates a misunderstanding of purpose of "REST web services" in general. The question concretely asks to perform two rather unusual tasks with a REST web service:

  1. Manipulating the HTTP session associated with the request.
  2. Redirecting to a HTML page managed by a stateful MVC framework as response.

Both squarely contradict the stateless nature of REST. Those tasks aren't supposed to be performed by a REST web service. Moreover, REST web services are primarily intented to be used by programmatic clients (e.g. JavaScript or Java code), not by webbrowsers which consume HTML pages. You normally don't enter the URL of a REST webservice in browser's address bar in order to see a HTML page. You normally enter the URL of a HTML page in browser's address bar. That HTML page can in turn be produced by a HTML form based MVC framework such as JSF.

In your specific case, after the programmatic client has retrieved the unique ID from the REST web service, then the programmatic client should in turn all by itself fire a new request to the JSF web application. E.g. as follows in Java based client (below example assumes it's a plain servlet, but it can be anything else as you said yourself):

String uniqueId = restClient.getUniqueId(userId, token);
String url = "http://example.com/context/login.xhtml?uniqueId=" + URLEncoder.encode(uniqueId, "UTF-8");
response.sendRedirect(url);

In the target JSF web application, just use <f:viewParam>/<f:viewAction> the usual way in order to grab the unique ID and perform business actions based on that. E.g. as below in login.xhtml:

<f:metadata>
    <f:viewParam name="uniqueId" value="#{authenticator.uniqueId}" />
    <f:viewAction action="#{authenticator.check}" />
</f:metadata>

@ManagedBean
@RequestScoped
public class Authenticator {

    private String uniqueId;

    @EJB
    private UserService service;

    public String check() {
        FacesContext context = FacesContext.getCurrentInstance();
        User user = service.authenticate(uniqueId);

        if (user != null) {
            context.getExternalContext().getSessionMap().put("user", user);
            return "/somehome.xhtml?faces-redirect=true";
        }
        else {
            context.addMessage(null, new FacesMessage("Invalid token"));
            return null; // Or some error page.
        }  
    }

    // Getter/setter.
}

Perhaps the REST webservice could for convenience even return the full URL including the unique ID so that the client doesn't need to worry about the target URL.

String uniqueIdURL = restClient.getUniqueIdURL(userId, token);
response.sendRedirect(uniqueIdURL);

On the other hand, there's a reasonable chance that you just misunderstood the functional requirement and you can just directly process the user ID and token in the JSF web application, the more likely if it runs at the same server as the REST web service and also uses HTTPS. Just add an extra <f:viewParam> and do the same business service logic as the JAX-RS resource in the <f:viewAction> method.

<f:metadata>
    <f:viewParam name="userId" value="#{authenticator.userId}" />
    <f:viewParam name="token" value="#{authenticator.token}" />
    <f:viewAction action="#{authenticator.check}" />
</f:metadata>

See also:

  • What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
  • How to implement JAX-RS RESTful service in JSF framework


回答2:

Try this in your code,

return new Viewable("/index", "FOO");

Or,

RequestDispatcher rd = request.getRequestDispatcher("{url}");
rd.forward(request, response);

Or,

return Response.status(myCode).entity(new Viewable("/index", "FOO")).build();


回答3:

try these example working in using jersey,

@GET
public Response get() {
    URI uri=new URI("http://nohost/context");
    Viewable viewable=new Viewable("/index", "FOO");
    return Response.ok(viewable).build();
}

to return something different use this approach:

@GET
public Response get() {
    int statusCode=204;
    Viewable myViewable=new Viewable("/index","FOO");
    return Response.status(statusCode).entity(myViewable).build();
}

Hope that helpe