A good code reads to let people drink, and after reading it, I am refreshing. If you want to improve your programming level, if you want to improve your design, if you want to become a master, then go to read the code. With the programming experience in my more than ten years, reading code can make you get more than reading articles (which fear is the master's article). Excellent and practical code there are a lot, such as JUnit, such as Jive, such as PetStore, or even Tomcat Example, Log4j's example. Struts-menu also comes from a master's work, Matt Raible. There are many excellent works, such as Struts-Resume using struts and hibernate. Official website is
http://raibledesigns.com/wiki/wiki.jsp?page=main
. The latest version of Struts-Menu is 2.1. The function is to use Struts technology to build a tree menu. It should be said to be a very practical technology, greatly facilitating the majority of developers. At the same time, individuals think that its role is more than just. For example, it is also a use
Maven
with
Velocity
A good example.
First, let's take a look at its effect. Http://www.raibledesigns.com/struts-meru/. It can be seen that such a colorful menu effect is to demonstrate the content in a configuration file. This is a very good data and the implementation of the phase separation. We open its source code. First look at its bag diagram
There are five packages, where Menu is naturally completed data organization, one of the cores, Displayer is a display method package, and the completion of data shows most of the features. It is also one of the cores. Taglib significance is obvious. EXAMPLE is naturally some examples. Util is a package that reads the resource file. Because of some of our focus on the package only three Menu, Displayer, and Taglib.
First let's see the class diagram of the Menu package.
The first is a category of menuPlugin. This class is obvious, it is a struts of Plug-in. It can be seen that it has only one parameter MenuConfig, which is the configuration file path of the MENU. Sure enough, there is such a paragraph in the Struts-Conf file.
Note The configuration file comes from /Web-inf/Menu-config.xml, of course, we can find this file under the corresponding path. If you haven't done Struts before, now I know how to do it, it is so simple. By reading the initialization function, knowing its function is to call MENUREPOSTORY to create a menu. therefore. We know that MenurePository is inevitably an organization class for an organization management management menu.
Public void init (ActionServlet servlet, Moduleconfig Config "throws servletexception {
IF (log.Indebugeload ()) {
Log.debug ("Starting Struts-Menu Initialization);
}
this.servlet = servlet;
Repository = new menuRepository ();
Repository.setloadparam (menuconfig);
Repository.setServlet (servlet);
Try {
Repository.load ();
servlet.getServletContext (). setttribute (SETATRIBUTE)
MenurePository.Menu_repository_key,
Repository);
IF (log.Indebugeload ()) {
Log.debug ("Struts-Menu Initialization SuccessFull);
}
} catch (loadableresourceexception LRE) {
Throw new servletexception
Failure Initializing Struts-menu: " Lre.getMessage ());
}
}
Open the menurepository class, we can see this class is also very simple, but there are fewer learning. The first is FasthashMap, you can see that there are three fasthashmap in this class. As the name, it is fast Hashmap, then look at it, it is from org.apache.commons.collections.fasthashmap; See the famous package of org.apache.commons? If you have never used it before, it is recommended that you spend a while to study using it, I promise value.
Protected fasthashmap menus = new fasthashmap (); protected fasthashmap displayers = new fasthashmap (); protected fasthashmap templates = new fasthashmap ();
Next we see the LOG definition. Right, Log, the core of debugging. The following sentence is the most commonly used method of use of the Commons log. Let your program use Commons log, first, it is powerful, second, it is simple, it is so simple.
Private log log = logfactory.getlog (getclass (). getname ());
Look at one function below
protected digesterinitdigester () {
Digester digester = new digester ();
Digester.SetClassLoad (thread.currentthread (). getContextClassLoader ());
Digester.push (this);
//digester.setdebug (getDebug ());
// 1
Digester.addObjectCreate ("MenuConfig / Menus / Menu",
"Net.sf.navigator.Menu.MenuComponent", "Type");
Digester.addSetProperties ("MenuConfig / Menus / Menu); Digester.addsetNext (" MenuConfig / Menus / Menu "," AddMenu ");
// 2
Digester.addObjectcreate ("MenuConfig / Menus / Menu / Item",
"Net.sf.navigator.Menu.MenuComponent", "Type");
Digester.AddSetProperties ("MenuConfig / Menus / Menu / Item");
Digester.AddsetNext ("MenuConfig / Menus / Menu / Item", "AddMenuComponent",
"Net.sf.navigator.Menu.MenuComponent");
// 3
Digester.addObjectcreate ("MenuConfig / Menus / Menu / Item / Item",
"Net.sf.navigator.Menu.MenuComponent", "Type");
Digester.AddSetProperties ("MenuConfig / Menus / Menu / Item / Item");
Digester.addsetNext ("MenuConfig / Menus / Menu / Item / Item",
"AddMenuComponent", "Net.sf.navigator.Menu.MenuComponent");
// 4
Digester.adDObjectCreate ("MenuConfig / Menus / Menu / Item / Item / Item",
"Net.sf.navigator.Menu.MenuComponent", "Type");
Digester.AddSetProperties ("MenuConfig / Menus / Menu / Item / Item / Item");
Digester.addsetNext ("MenuConfig / Menus / Menu / Item / Item / Item",
"AddMenuComponent", "Net.sf.navigator.Menu.MenuComponent");
//5
Digester.addObjectcreate ("MenuConfig / Menus / Menu / Item / Item / Item / Item",
"Net.sf.navigator.Menu.MenuComponent", "Type");
Digester.AddSetProperties ("MenuConfig / Menus / Menu / Item / Item / Item / Item");
Digester.addsetNext ("MenuConfig / Menus / Menu / Item / Item / Item / Item",
"AddMenuComponent", "Net.sf.navigator.Menu.MenuComponent");
//6
Digester.addObjectcreate ("MenuConfig / Menus / Menu / Item / Item / Item / Item",
"Net.sf.navigator.Menu.MenuComponent", "Type");
Digester.addSetProperties ("MenuConfig / Menus / Menu / Item / Item / Item / Item"); Digester.AddsetNext ("MenuConfig / Menus / Menu / Item / Item / Item / Item",
"AddMenuComponent", "Net.sf.navigator.Menu.MenuComponent");
// 7
Digester.addObjectcreate ("MenuConfig / Menus / Menu / Item / Item / Item / Item",
"Net.sf.navigator.Menu.MenuComponent", "Type");
Digester.AddSetProperties ("MenuConfig / Menus / Menu / Item / Item / Item / Item");
Digester.addsetNext ("MenuConfig / Menus / Menu / Item / Item / Item / Item",
"AddMenuComponent", "Net.sf.navigator.Menu.MenuComponent");
Digester.addObjectcreate ("MenuConfig / Displayers / Displayer",
"net.sf.navigator.displayer.menudisplayermapping", "mapping");
Digester.AddSetProperties ("MenuConfig / Displayers / Displayer");
Digester.AddSetNext ("MenuConfig / Displayers / Displayer",
"addmenudisplayermapping",
"net.sf.navigator.displayer.menudisplayermapping");
Digester.AddSetProperty ("MenuConfig / Displayers / Displayer / SetProperty",
"Property", "Value");
Return Digester;
}
Here is a classic, Digester, Digester's use, if you need to read an XML configuration file, do not want to deal directly with DOM, Digester will be a good choice. In fact, we see the load function calls a digester.parse (INPUT); it has been built into memory, which is as simple as it is. If you want to initialize your system, is this way to learn? "Want to do something, you must first sharpen it." We can see how Raible uses existing tools to mitigate the development.
Due to menurepository weightlifting, if you don't even let us see how the tree structure is built to the memory. But don't worry, the class map gives us expressive.
Did you see the Menubase class? Yes, look at the name, you know that it is a matrix class. It can be seen that it is a simple JavaBean. And I believe that each attribute of it can guess according to the name. So the focus is MenuComponent, a simplified "Composite" mode.
As shown in FIG. Because the Leaf here, there is no method, only attributes. Therefore, Leaf and Composite contractions become a MenuComponent class. Everyone knows that the Composite mode is the best way to achieve the tree structure. If you have not had a chance to achieve or have a good place from Composite mode, then look at it here. First look at it, the actual code of Menucomponet is very small, adding less than ten lines. Public void addmenucomponent (MenuComponent menucomponent) {
MenuComponents.add (menucomponent);
Menucomponent.SetParent (this);
IF ((menucomponent.getname () == NULL) ||
(menucomponent.getname (). Equals ("")))) {
MenuComponent.setName (this.name menucomponents.size ());
}
}
Public menucomponent [] getMenuComponents () {
MenuComponent [] Menus =
(Menucomponent []) MenuComponents.toArray (_MenuComponent);
Return Menus;
}
If you use ten lines to implement a tree structure (and still universal), would you like it? That is to create the target of the tree structure in memory by simple such code.
Let's take a look at the Display package, this package is also very clear, it is used to show. The class diagram of this package is very beautiful, and unfortunately is very large. Can only be reduced to everyone.
From the class diagram, you can see a very beautiful iconic object design idea. Through an interface, the template method is utilized. Finally, the display of the tree structure is realized. Its main approach is DISPLAYCOMPONENTS and DISPLAY, the init method implements the initialization work, read files such as JavaScript and pictures. DisplayComponents is an iterative function. Thereby, a MenucomPont tree can be traversed. And display it.
It should be said that the Menu package is a M layer, and the Dispplya package is a View layer, and the TAGLIB package is added to the full structure of the MVC.
Two TAG classes are very clear, first we use it to see their functions
Obviously. UseMenudisplayer This class is to implement which display method for use. We see the definition of ListMenu in Menu-Config