The good news is that a lot of people have been using J2EE containers to solve the very same problems you’re likely to encounter. They found reoccuring themes in the nature of the problems they were dealing with, and they came up with reusable solutions to these problems. These design patterns have been used, tested, and refined by other developers, so you don’t have to reinvent the wheel.
A software design pattern is “a repeatable solution for a commonly-occuring software problem.”
The most important job for a web app is to provide the end user with a reliable, useful, and correct experience. In other words, the program must satisfy the functional requirements such as “select a beer style” or “add malt to my shopping cart”. Once you’ve made sure that the system supports the use cases, you’ll most likely be faced with another set of requirements—requirements for what happens behind the scenes, i.e. the non-functional requirements.