Most developers would consider accessing a database part of the "business end" of an application. Most often, we don't access a database for the sake of accessing a database. We use the database as part of a larger business transaction. So lets start with accessing business logic from the framework.
The best thing is to use the Action as a thin adaptor between the web/presentation-tier and your business classes (including those that access a database).
So you first design a business API that uses plain Java classes. The best thing is to use objects that take ordinary Java types and return a JavaBean or collection of JavaBeans. The Action then calls these objects and passes the result back to the web/presentation tier.
A common approach is to create an Action class for each of business transaction, or use case, in your application. A simple "CRUD" application might have a CreateAction, a RetrieveAction, an UpdateAction, and a DeleteAction. To complete each transaction, the Action can make whatever calls are needed to your business API classes.
Ideally, all the database access code should be encapsulated behind the business API classes, so the framework doesn't know what persistent layer you are using (or even if there is a persistence layer). It just passes a key or search String and gets back a bean or collection of beans. This lets you use the same business API classes in other environments, and also to run unit tests against your business API outside of a web environment.
The Struts MailReader shows how this is usually done. MailReader uses the DAO (Data Access Object) pattern to separate the persistence layer from the (Struts) control layer. MailReader defines a DAO interface that the Actions can call, it then defines a implementation that uses a database stored in main memory. Other implementations could be defined and used instead, without changing any of the Struts classes.
To get started, it's simplest to setup a 1:1 correspondence between the Actions and your application's use cases. Each use case may make one or more calls to your business API, but from the user's perspective, each use case is a single transaction.
As you gain experience, you will find ways to combine your Action classes, say by using the DispatchAction. It's even possible to use a single "framework" Action to call all of your business classes, as is done with Scaffold ProcessAction in the Sandbox subproject.
Using fewer Actions does require a deeper understanding of how Struts and MVC frameworks operate. Don't hesitate to err on the side of creating more Action classes at first. The configuration file makes it easy to refactor your Actions later, since you can change the Action type without changing anything else in the application.
When you use the DAO approach, all of the database access
hidden behind the business interface. The implementation of
classes handle all the gritty details, like using a
to pool connections to the database.
As a rule, you should always use a connection pool to access a
interface is the preferred way to implement a
connection pool today. Many containers and database systems
a DataSource implmentation that you can use. Most often, the
is made available through JNDI. The JNDI approach makes it
easy for your
business classes to access the DataSource without worrying
about who set it
There are many useful and mature persistence layer frameworks available. Before using raw JDBC or "rolling your own" solution, you should carefully review one or more of these packages. Here's a short list of packages most often mentioned on the Struts User list:
For more, see the Struts Community Resources area on SourceForge.
The result of most queries will map to the ActionForms you are already using, and so you can render the ResultSet as a collection of ActionForms. But sometimes there are columns in a ResultSet that are not properties of an ActionForm, or even known in advance.
Happily, the Struts JSP tags don't care what type of bean you use with them. You could even output a ResultSet directly. But a ResultSet retains a connection to the database, and passing "all that" directly to a JSP gets messy. So what's a developer to do?
Since version 1.1, the simplest option is to use a ResultSetDynaClass to transfer the ResultSet into an ArrayList of DynaBeans. The Struts custom tags can use DynaBean properties as easily as they use conventional JavaBean properties. (See DynaActionForm classes in the Struts User Guide for details.)
Since these classes are in the BeanUtils JAR, you already have it on board, and just need to implement the transfer routine (see the ResultSetDynaClass link).