Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

jsf - How to handle multiple submits before response is rendered?

It has been reported from testing that it is occasionally possible to press a button more than once if the response is not rendered fast enough, causing several invocations of the back-end code, which we do not want.

Application is Java EE 6 Web Profile using JSF 2.0 inside Glassfish 3.1.1.

I was wondering how this should be properly dealt with, and have thought of a few scenarios:

  • Submitting should disable all buttons using javascript while response is being rendered.
  • A flag in the Session scope saying it is already active, so the sensitive code is skipped and just moves on to the re-rendering of the response for the previous submit.
  • A synchronized block delaying the processing until the previous request have finished. Then it should be detected that it has been already processed and skipped.
  • Using one of the "new" scopes like conversion to handle the detection?

My immediate gut feeling is that the best approach is to have sensitive code blocks atomic, but then the problem is with rendering the correct response.

How should I approach this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Submitting should disable all buttons using javascript while response is being rendered.

This is the easiest to implement in a generic manner. If you happen to use <f:ajax> exclusively, you could use the jsf.ajax.addOnEvent() to perform the job in a generic manner. An alternative JavaScript approach is to create kind of an "Loading" overlay which blocks the UI so that the enduser won't be able to interact with the underlying page anymore. This is basically an absolutely positioned hidden <div> which spans the entire viewport with some opacity (transparency). You could show it on submit and hide it on render. The keyword for this technique is "modal dialog". UI-oriented JSF component libraries have at least such a component already in their assortiment. E.g. PrimeFaces with a <p:dialog modal="true"> inside a <p:ajaxStatus>, or the <p:blockUI>

The only disadvantage is that it won't work if the client has JS disabled or don't use it and it thus won't prevent HTTP clients from double submits.


A flag in the Session scope saying it is already active, so the sensitive code is skipped and just moves on to the re-rendering of the response for the previous submit.

This is more known as "synchronizer token pattern" and has ever been requested for JSF by spec issue 559 which is currently on the ticket targeted for 2.2, but there doesn't seem to be any activity on it. The detection and blocking part is technically easy to implement, but the synchronous response handling part is not easy to implement if you want that the enduser ultimately retrieves the response as generated by the initial request. The asynchronous response handling is easy: just don't specify any components to update, i.e. empty the collection as returned by PartialViewContext#getRenderIds(). After all, this is more robust than using JS to disable the buttons or block the UI.

As far as I know, Seam 2 was the only who offered a reuseable JSF component for this, the <s:token>. I must however admit that this is an interesting idea for a new OmniFaces component. Maybe I will personally take a look at it.


A synchronized block delaying the processing until the previous request have finished. Then it should be detected that it has been already processed and skipped.

This is not easy to implement generically, this would require a change in all action methods to check if the job is already done. It also won't work if the webapp runs on multiple servers. A synchronizer token is easier as it would be performed before the action methods are invoked. A synchronizer token is also less expensive as you don't end up with multiple requests in the queue which would only cost threads/resources.


Using one of the "new" scopes like conversion to handle the detection?

This problem cannot be solved by playing around with managed bean scopes. Managed bean scopes serve a different purpose: the lifetime of the bean instance.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...