An excellent way to design your project package structure is to classify packages initially by technology. So in a Click application all of our pages would be contained under a page package. This also works very well with the Page automapping feature.
All the projects domain entity classes would be contained under a entity package, and service classes would be contained under a service directory. Note alternative names for the entity package include domain or model. We also typically have a util package for any stray classes which don't quite fit into the other packages.
In Java, package names are singular by convention, so we have a util package rather than a utils package.
An example project structure for a MyCorp web application is illustrated below:
In this example application we use declarative role and path based security.
All the pages in the admin package and directory require the
"admin"
role to be access, while all the pages in the
user package and directory require the "user"
role to be accessed.
A best practice when developing application Page classes is to place common methods in a base page class. This is typically used for providing access methods to application services and logger objects.
For example the BasePage below provides access to Spring configured service objects and a Log4J logger object:
public class BasePage extends Page implements ApplicationContextAware { /** The Spring application context. */ protected ApplicationContext applicationContext; /** The page Logger instance. */ protected Logger logger; /** * Return the Spring configured Customer service. * * @return the Spring configured Customer service */ public CustomerService getCustomerService() { return (CustomerService) getBean("customerService"); } /** * Return the Spring configured User service. * * @return the Spring configured User service */ public UserService getUserService() { return (UserService) getBean("userService"); } /** * Return the page Logger instance. * * @return the page Logger instance */ public Logger getLogger() { if (logger == null) { logger = Logger.getLogger(getClass()); } return logger; } /** * @see ApplicationContextAware#setApplicationContext(ApplicationContext) */ public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } /** * Return the configured Spring Bean for the given name. * * @param beanName the configured name of the Java Bean * @return the configured Spring Bean for the given name */ public Object getBean(String beanName) { return applicationContext.getBean(beanName); } }
Applications typically use a border template and have a
BorderPage
which extends BasePage
and defines the template. For example:
public class BorderPage extends BasePage { /** The root Menu item. */ public Menu rootMenu = new Menu(); /** * @see Page#getTemplate() */ public String getTemplate() { return "/border-template.htm"; } }
Most application pages subclass BorderPage
, except
AJAX pages which have no need for a HTML border template and typically extend
BasePage
. The BorderPage
class
should not include common logic, other than that required for rendering the
border template. Common page logic should be defined in the
BasePage
class.
To prevent these base Page classes being auto mapped, and becoming
directly acessible web pages, ensure that there are no page templates which
could match their class name. For example the BorderPage
class above will not be auto mapped to border-template.htm
.