Build a Web server that belongs to you--Configure controller

Source: Internet
Author: User

This day a hot, Fat Man's world is a miserable ah, casually move body, and wash a bath like, the mood is irritable, a irritability will be very difficult to write things down the heart ... So this paragraph did not write attentively, a little water point bar, at the same time, I also intend to lose weight!>_<!.

The last time we introduced the session implementation, so that the Web server (now always feel that it should be called independently deployed web framework, not the server) has the basic function, but a careful thought will find a serious problem: whenever a new controller is implemented, Then you need to add judgment in the Invokcontroller method so that the URL can find the corresponding controller. For a Web server (or framework), the internal should be closed, even to support the expansion should be to provide external interface implementation, by changing the code to modify, is definitely a very bad design. Let's look at several implementations:

first, how to achieve

Let's start by thinking about how a URL request is mapped to the corresponding processing method, and the general idea is as follows:

you can see that there are two key points in this: 1. How does the routing table structure be implemented? 2, how to find the corresponding class of the object is how to load (instantiation)? As long as the two problems are clear, in fact everything will be solved.
The main function of the routing table is to find the corresponding corresponding processing class by the URL, we can easily think of the structure is the map of the key-value structure, in fact, most of the situation is true. However, it is important to note that, in the actual storage, the specific content depends on the situation, in simple case, the direct key stored uri,value stored processing class information, but when you want to support a variety of mapping rules (such as prefix matching, regular matching, etc.), it will be classified storage. In general, this part is easy to achieve.
Let's take a look at the second problem, where the routing table generally stores the class information (as far as the mapping to a specific method), and in most cases just the class name, but the actual processing requires the class object to execute. Then we need to consider how these class objects are loaded. One approach is to instantiate all registered classes (which should also be reflected) when the Web server is started, and the other is to dynamically generate objects by reflection based on the class name at the time of use, but the difference is only the time when the object is instantiated. (Here comes a question, in general, the object instantiated here should be a singleton, that is, the same request object is a, concurrent processing in the internal implementation of the device, the project is currently not considered this, and will be improved later)

second, the function design

to design first, this time is relatively simple, for the routing table we currently only need to support the URI and controller one by one corresponding to the case, so directly using a map storage is good. and the configuration to facilitate directly through the annotation implementation (before the configuration file configuration, and then removed, if necessary, you can add it yourself), the Web server starts with the development of all controller type annotations in the directory, and then based on the annotation information map into map. When a URL is requested, the corresponding class name is found from the map, and the corresponding method is instantiated and invoked by reflection.

Third, the implementation of code

First look at the definition of annotations ( Java Custom Annotations ), where two annotations are defined, one is the mapping of the URL, and the other is a method map (only the method that declares the annotation is mapped ):

 Packageorg.eh.core.annotation;Importjava.lang.annotation.Documented;ImportJava.lang.annotation.ElementType;Importjava.lang.annotation.Retention;ImportJava.lang.annotation.RetentionPolicy;ImportJava.lang.annotation.Target;/*** Controller Annotations *@authorguojing * @date 2014-3-5*/@Retention (retentionpolicy.runtime) @Target (elementtype.type) @Documented Public@InterfaceController {/*** Controller name, temporarily useless*/     PublicString name (); /*** Corresponding URL request path, such as Htp://127.0.0.1/test/list.do, the corresponding controller is:/test/, the corresponding method is: List*/     PublicString URL ();}/*** Method Map Annotations *@authorguojing * @date 2014-3-13*/@Retention (retentionpolicy.runtime) @Target (elementtype.method) @Documented Public@Interfacerequestmapping {}

define the annotations and then implement a annocationhandler processing Annotation Information , this class mainly implements three functions: 1. gets all the class names (including package names) under the specified package, 2. Add all note Controllers to constants.urlclassmap,3. Gets the specified method of the class , which is implemented as follows:

/*** Annotation Processing class *@authorguojing * @date 2014-3-5*/ Public classAnnocationhandler {/*** Add all Note controllers to Constants.urlclassmap *@paramParkage class name (including package path)*/@SuppressWarnings ({"Unchecked", "Rawtypes" })     Public voidPasercontrollerannocation (String parkage)throwsclassnotfoundexception {List<String> classlist =Getpkgclass (parkage);  for(String str:classlist) {Class C=class.forname (str); if(C.isannotationpresent (Controller).class) {Controller desc= (Controller) c.getannotation (Controller).class);            Constants.UrlClassMap.put (Desc.url (), str); }        }    }    /*** Gets all class names (including package names) under the specified package *@paramParkage specifying the package name *@return     */     PublicList<string>Getpkgclass (String parkage) {string path= Constants.class_path + Parkage.replace (".", "/") + "/"; List<String> list =NewArraylist<string>(); File File=NewFile (path);  for(String str:file.list ()) {if(Str.endswith (". Class")) {list.add (parkage+ "." + Str.replace (". Class", "" ")); } Else if(Str.indexof (".") = =-1) {List.addall (Getpkgclass (Parkage+ "." +str)); }        }        returnlist; }        /*** Get the specified method of the class *@paramc *@paramMethodName*/@SuppressWarnings ({"Unchecked", "Rawtypes" })     PublicMethod GetMethod (Class C, String MethodName)throwsNosuchmethodexception, SecurityException {method= C.getmethod (MethodName, Map.class); returnMethod.isannotationpresent (requestmapping.class) ? Method:NULL; }}

and then in Ehhttphandler's the Invokcontroller method passes the reflection ( Java Reflection ) Call the method, as follows:

/*** Call the corresponding controller to process the business*/    Privateresultinfo Invokcontroller (Httpexchange httpexchange) {String path=Httpexchange.getrequesturi (). GetPath (); String ClassPath= Constants.UrlClassMap.get (path.substring (0, Path.lastindexof ("/") + 1)); if(ClassPath = =NULL|| Classpath.length () = = 0) {            return NULL; } Class Controllerclass=Class.forName (ClassPath); Controller Controller=(Controller) controllerclass.newinstance (); String MethodName= Path.substring (Path.lastindexof ("/") + 1, Path.lastindexof (".")); //get the corresponding method by reflectionAnnocationhandler Annocationhandler =NewAnnocationhandler (); Method Method=Annocationhandler. GetMethod (Controllerclass, methodName); Map<string, object> map =NULL;//ParametersMap =analysisparms (Httpexchange); //Set SessionHttpSession HttpSession =Applicationcontext.getapplicationcontext (). getsession (Httpexchange); Map.put ("Session", httpSession); return(resultinfo) Method.invoke (Controller,Newobject[] {map}); }

Finally, load the configuration information at startup and Ehserver's Add in StartServer

// Controller that loads the annotation configuration        New Annocationhandler ();         Try {            Annocationhandler                    . Pasercontrollerannocation ("Org.eh.core.web.controller");         Catch (Exception e) {            log.error ("Loading controller configuration Error! ", E);             return ;        }

This completes the function.

Iv. Testing

Let's test whether the function is useful or Indexcontroller, let's add the note information:

/*** Contoller for home page *@authorguojing*/@org. Eh.core.annotation.Controller (Name= "session", url = "/session/") Public classIndexcontrollerImplementscontroller{@RequestMapping PublicResultinfo process (map<string, object>map) {Resultinfo result=NewResultinfo (); //Here we determine if there is a name parameter in the request, if there is a session, no then remove the name from the session into the mapHttpSession session = (HttpSession) Map.get ("session")); if(Map.get ("name")! =NULL) {Object name= Map.get ("name"); Session.addattribute ("Name", name); } Else{Object name= Session.getattribute ("name"); if(Name! =NULL) {Map.put ("Name", name); }} result.setview ("Index");        Result.setresultmap (map); returnresult; }}

Then the browser opens the http://localhost:8899/session/process.do?name=guojing, and the result sees this familiar page again, explains all OK, You can also write more controllers, directly add annotations to access, without changing any other code .

v. Summary

    as a matter of fact, this project is actually used, but if you really intend to use it, you will find a lot of uncomfortable places, such as this project code and business code mixed together, Template support is too poor, configuration information written in the code and so on, then next time we will solve these problems.
     final source, learn-3 source (corresponding   master   For the full project):   source  

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.