This is a very common problem with a fairly standard solution. Whenever you generate your form, you should generate a unique token like a GUID and stick it in SQL, redis, memcached, the session, or any short term persistent store you have. Stick it in a hidden field. You should be doing one token for each generated form.
When the form gets submitted, atomically check for and remove the token from the store. If it's there the form was submitted for the first time. If not, it's a duplicate.
For bonus points, instead of showing an error on the second submission, you can store the token with the successful result data and use it to render the same success page as you would have if they clicked once.