The Salesforce docs for the inputFile Visualforce component has an example of uploading a document using the Standard Controller. Here is a quick example of using a Custom Controller in case you want to make the upload process part of a larger transaction.
Make sure you take a look at the finally block in the controller below. The finally block always executes when the try block exits regardless if an error occurs or not. You need to ensure you clear out document's body (document.body = null) so that the blob is not automatically included in the serialized image of the controller. If you do not clear out the body, you'll get the following view state error:
Maximum view state size limit (128K) exceeded. Actual viewstate size for this page was...