Struts-menu source code analysis

Source: Internet
Author: User
Good code can be easily read. After reading the code, it will be refreshing. If you want to improve your programming skills, if you want to improve your design capabilities, and if you want to become a master, read the code. With more than 10 years of programming experience, you can get more information by reading code than reading an article (even a master's article. There are many excellent and practical code, such as JUnit, such as jive, such as PetStore, or even Tomcat Example and log4j example.

Struts-menu is also 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 Struts-menu version is 2.1. The function is to use STRUTS technology to build a tree menu. It should be said that it is a very practical technology that greatly facilitates the majority of developers. At the same time, I personally think it has more than just a few functions. For example, it is also a good example of using Maven and velocity.

First, let's take a look at its effect. Http://www.raibledesigns.com/struts-menu /. As you can see, such a variety of menu effects are all in the demonstration of a configuration file. This is a very good implementation of separation of data and representation. Let's open its source code. First, let's take a look at its package diagram.

There are five packages in total. Menu is naturally one of the core functions of data organization, and displayer is the display mode package, which completes most of the data display functions. Is also one of the core. Taglib has obvious significance. Examples are examples. Util is the package for reading resource files. Because, we focus on only three menus, displayer and taglib.

First, let's look at the class diagram of the menu package.

The first is the menuplugin class. The function of this class is obviously a struts plug-in. As you can see, it only has one parameter menuconfig, which is the configuration file path of menu. Sure enough, there is such a section in the Struts-conf file.

  <!-- ========== Plug Ins Configuration ================================== -->

<Plug-in classname = "net. SF. Navigator. Menu. menuplugin">
<Set-Property = "menuconfig" value = "/WEB-INF/menu-config.xml"/>
</Plug-in>

Description of the configuration file from/WEB-INF/menu-config.xml, of course, we can find the corresponding path to find this file. If you have never done struts plug-in before, you should know how to do it now, that's simple. By reading the initialization function, we know that its function is to call menurepository to create a menu. Therefore. We know that menurepository must be an organizational class of the organization management menu.

public void init(ActionServlet servlet, ModuleConfig config) throws ServletException { if (log.isDebugEnabled()) { log.debug("Starting struts-menu initialization"); }  this.servlet = servlet; repository = new MenuRepository(); repository.setLoadParam(menuConfig); repository.setServlet(servlet);  try { repository.load(); servlet.getServletContext().setAttribute( MenuRepository.MENU_REPOSITORY_KEY, repository);  if (log.isDebugEnabled()) { log.debug("struts-menu initialization successfull"); } } catch (LoadableResourceException lre) { throw new ServletException( "Failure initializing struts-menu: " + lre.getMessage()); } }

Open the menurepository class, and we can see that this class is also very simple, but there is little to learn. The first is fasthashmap. We can see that there are three fasthashmaps in this class. Taking care of the hashmap, It is a quick hashmap. Let's take a look at it again, it comes from org. Apache. commons. Collections. fasthashmap ;. What about the famous org. Apache. commons package? If you have never used it before, it is recommended that you spend some time researching and using it, and I guarantee it is worth the money.

Protected fasthashmap menus = new fasthashmap ();
Protected fasthashmap displayers = new fasthashmap ();
Protected fasthashmap templates = new fasthashmap ();

Next we will see the definition of log. By the way, log is one of the core debugging tasks. The following sentence is the most commonly used method of commons log. Let your program use commons log. First, it is powerful. Second, it is easy to use.

Private log = logfactory. getlog (getclass (). getname ());

Let's look at a function.

 protected Digester initDigester() {         Digester digester = new Digester();         digester.setClassLoader(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;     }

It is also a classic, digester, and digester. If you need to read an xml configuration file and do not want to deal with Dom directly, digester is a good choice. In fact we can see that the load function calls a digester. parse (input); has built the menu-config.xml into the memory, it is so simple. Can this method be learned if you want to initialize your system? "To do well, you must first sharpen your tools ". We can see how raible uses existing tools to reduce development workload.

Since the menurepository initialization process is very lightweight, we don't even see how the tree structure is built into the memory. But don't worry. The class chart is explicit.

Have you seen the menubase class? By the way, you can see that the name is the base class of a menu. As you can see, it is a simple JavaBean. I believe that every attribute can be guessed by name. Therefore, the focus is on menucomponent, a simplified "composite" mode.

As shown in. Because leaf does not have any method, only attributes are available. Therefore, leaf and composite are reduced to a menucomponent class. As we all know, the composite mode is the best way to implement a tree structure. If you have no chance to implement or do not benefit from the composite mode before, let's take a look at the benefits of using the composite mode. First of all, let's take a look at its simplicity. menucomponet has very few actual code and adds up to less than 10 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 rows to implement a tree structure (and still generic), would you like? It is through some simple code to achieve the goal of establishing a tree structure in the memory.

Next let's look at the display package. The function of this package is also very clear, that is, it is used for display. The class diagram of this package is very beautiful, and unfortunately it is also very large. It can only be reduced to show you.

From the class diagram, we can see the design idea of a very beautiful facial image object. Use the template method through an interface. Finally, the tree structure is displayed. The main methods are displaycomponents and display. The init method implements initialization and reads JavaScript, images, and other files. Displaycomponents is an iterative function. This allows you to traverse a menucompont tree. And display it.

It should be said that the menu package is an m layer, and the dispplya package is a view layer. With the taglib package, the complete structure of MVC is realized.

The two tag classes are very clear. First, let's look at their functions from how they are used.

<Menu: usemenudisplayer name = "listmenu"
Bundle = "org. Apache. Struts. Action. Message">
<Menu: displaymenu name = "todolistmenufile"/>
<Menu: displaymenu name = "todolistmenuedit"/>
<Menu: displaymenu name = "casedetailmenucase"/>
<Menu: displaymenu name = "standalone"/>
</Menu: usemenudisplayer>

Obviously. Usemenudisplayer is a display method used by this class. In menu-config, we can see the definition of listmenu.

<Displayer name = "listmenu"
Type = "net. SF. Navigator. displayer. listmenudisplayer"/>

Displaymenu is used to obtain and display a menu, which can also be found in menu-config.

<Menu  name="ToDoListMenuEdit"  title="EDIT">
<Item name="TDLselect" title="SELECT_ALL" image="images/select-all.png"
location="index.jsp" width="100" />
<Item name="TDLprefs" title="USER_PREFERENCES" image="images/prefs.png"
location="index.jsp" width="150" />
<Item title="Action Test" action="setPermissions?displayer=${displayer}"/>
</Menu>

View the displaymenu code. The function is to retrieve the menucomponent object from the context, and then assign it to a menudisplayer instance through displayer. Display (menu.

Therefore, the control layer completes the control function.

To sum up. Through such a beautiful design, he left all functions. If we need to add a display method, we only need to inherit menudisplayer or a subclass of it, and then write out our method without modifying other parts of the system. Similarly, if the menu is not stored in servletcontext and is to be stored in session, we only need to modify the control part and the generated part (I .e. the menurepository. The display part is not affected.

OK. The introduction to Struts-menu is complete. The next article will show how to use Struts-menu and database technology to dynamically generate menus. Please follow up on my blog.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.