This article mainly implements Struts's request forwarding function. Other functions will slowly make up.
Recently, I learned the content of Javassist, and I saw an article. Everyone wrote the MVC mainly describing the workflow of the MVC, and at the same time realized the simple Struts2 function.
Here is a simple Struts2 framework, and at the same time, you add some of your own understanding.
This article mainly implements Struts's request forwarding function. Other functions will slowly make up.
First of all, in the Struts2 framework, the implementation and jump of requests are mainly configured by struts.xml. A <ACTION> label indicates a definition of a request, which contains the name "name" of the request; ② the corresponding implementation class "class"; Configure the Execute0 method by default. The <ReSult "label defines the type" name "of the result, including 'Success', 'None', 'Login', 'Input', 'Error'; ② The type" Type ", including 'Dispatcher (default)' '' , 'Chain', 'Redirect', 'RedirectAction', 'Stream'; ③ jump of results. After configuring the struts.xml, the form in the interface can find the corresponding ACTION tag through the name attribute value defined by the ACTION property, so as to find the corresponding class and execution methods. Then match the String string returned by the execution method to match the name in the Result tag, and perform the next request operation according to the defined Type type.
Well, after understanding how Struts2 connects the interface requesting the same program function, we can implement this part of the function through our own code.
So how do we start?
We will be divided into two parts with simple functions ①ACTION part ②ReSult part
the action part
① We need to find the corresponding class and execution methods according to the request of the interface
result part
① We need to return the type string of 'Success', 'None', 'Login', 'Input', and 'Error'
② Different types of request address need to be specified for different types of returning
③ The types that need to be defined, including 'Dispatcher (default)', 'Chain', 'Redirect', 'RedirectAction', 'Stream'
In this article, the return types of Result only realize the two types of 'Success' and 'Login', and for the time being, they do not consider the type of request. The default Dispatcher request forwarding type is implemented. The perfect function will be replenished later.
Then, let's see how to achieve the above function through the code.
Firstly, the two custom annotations of Actionannotation and ResultAnNotation request the corresponding method and method of the string returned by the two custom annotations of Actions
/ ** * Action Note: ActionName is equivalent to the URL -PATTERN * @author Linling * */ @RETENTION (RetentionPolicy.runtime) @Targettype.Method BLIC @Interface ActionsNotation {String ActionName () default ""; Resultannotation [] results () default {};} /*** Return to the annotation object: name is equivalent to the name of the result in the struts configuration, including 'Success',' None ',' Error ',' Input. ', 'Login'; Value is equivalent to the corresponding return jump content in the Struts configuration * @Author Linling * */ @RETENTION (RetentionPolicy.runtime) @Target (ElementType.method) Resultannotation {resulttype name () default resulttype.success; String value () default "index.jsp";}
Then we define an ActionContext class to save the content required for a request
/*** Implement the simulation struts jump to the content required to execute the corresponding method according to the configuration file* @AutHor Linling**/Public Class ActionContext {/*** equivalent to URL -Pattern in the web.xml, the only*/ Private String url; /*** Actionannotation comments corresponding method, that is, the method to execute in the action* /private string method; /*** Actionannotation type, corresponding to the type returned by the action method. For example: Key: 'Success'; Value: 'Index.jsp'* / Private Map <ResultType, String> Results; / ***Action class* / private class <?> ClasStyStype; / ** * Action object* / Private Object Action; / *** method parameter type type* / private class <?> [] paramStype; / *** method parameter name, note that the method name here needs to be coupled with the above paramtype parameter* Attributes in Action* / Private String [] ActionParamsname; / *** The httpservletRequest* / PrivatevletRequest REQUEST; / *** The requested httpservlet is Response */ Private httpservletresponse response;
AnalysePackage is a method required for assembling ActionContext
/** * traversed the Class file under the scan_package package, which uses the method of Actionannotation to analyze it, assembled it into an ActionContext object and put it in the URLMAP * @param Real_path scan_package * @Thro WS ClassNotFoundexception * @throws InstantiationException * @throws IllegalaccessException * @Throws NotFoundexception */ Public Static Void AnalysePackage (String Real_Path, String Scan_package Foundexception, InstantificationException, iLlegalaccessException, NotFoundexception {file file = new file (reaL_Path); if (file.isdirectory ()) {file [] f (] f iles = file.listFiles (); for (F: F: Files) {AnalysePackage (f.getabsolutepath (), scan_package); ); IF (Str.indexof ; dexof (". class" ); Class <?> ClassStype = Class.Forname (FILENAME); Method [] Methods = ClassStype.getMethods (); for (Method Method: Method.isan NottingPressnt (ActionanNotation.class) {ActionContext ActionContext = New ActionContext (); ActionanNotation Actionannotation = (Actionannotation) Method.Getannotation (Actionannotation.class); String Url = Actionannotation.ACT IONNAME (); Resultannotation [] results = actionannotation.Results (); if (url.isempty () || results .length <1) {Throw New RuntimeException ("Method Annitation Error!" + Method + ", ActionName:" + URL + ", Result.Length:" + Results.Lengts.Lengt h);} ActionContext.seturl (url); ACTIONTEXTEXT.SetMethod (METHOD.GetName ()); Map <res) map = new hashmap <res) (); for (resultannotation result: SULTS) {string value = result.value (); if (value. Isempty ()) {Throw New Runtimeexception ("Result name () is null");} Map.put (result.name (), value);} ActionContext.Setresults (Map); Act IONCONTEXT.SETCLASSTYPE (ClasStype); ActionContext. SetACTION (ClasStype.newInstance ()); ActionContext.SetParamStype (Method.GetParametertypes ()); ActionContextParamsName Sname (CLASSTYPE, METHOD.GetName ())); urlmap.put (url, actionContext);}}}}}
GetParams is a request parameter array based on the request content in the httpservletRequest request.
/** * Based on the parameter type Parastype and parameter name ActinParamsname to analyze the request Request to build a parameter Object [] * @param Request * @paramstype * @Param ActionParamsname * @Retourn * @ ThROWS InstantiationException * @throws iLlegalaccessException * @throws Illegalargumentexception * @ @ @ @ @ @ @ Throws InvolutionAntargetexception * @throws NosuchmedHodexception * @throws SecurityException */ Public Static Object [] Quest Request, Class <?> [] ParamStype, String [] ActionParamsName) Throws InstantiationException, IlLegalaCcessException, IlLegalagumentedException, Invocat IontarGexception, NoSuchMethodexception, SecurityException {Object [Object ] Objects = New Object [ParamStype.length]; for (int i = 0; I <ParamStype.length; I ++) {Object Object = Null; if (Paramsutill.isbasicType (PARAMPE style [i])) {Objects [i] = Paramsutils.getparam (request, paramStype [i], actionparamsname [i]);} Else {class <?> Classtype = ParamStype [i]; ; Field [] fields = classstype.getDeTDECLARDFIELDS (); For (Field Field: Fields) {map <string, string []> map = request.getparametermap (); for (Iterator <string> Iterator = MAP.KEYSET (). Iterator.hasnext ();) {{ String key = Iterator.next (); if (key.indexof (".") <= 0) {Continue;} string [] strs = key.split ("//."); If (strs.Length! = 2) {Continue;} if (! ActionParamsName [i] .equals (strs [0])) {Continue;} if (! Field.getName (). Equals (strs [1])) {Continue;} String Value = map.get (key) [0]; ClasStype.getMethod (convertoFieldtoseTMethod (Field.getName ()), Field.gettype ()). Invoke (Object, Value); Break; bjects [i] = object;}} Return objects;}
Okay, next. We can implement the Action method
Public class loginaction {@ACTIONNOTATION (ActionName = "Login.action", Results = { @ResultAnitation (name = Resulttype.Success, Value = "I ndex.jsp "),@resultannotation (name = resulttype.login, value =" login. jsp ")}) Public Resulttype Login (String name, String Password) {if (" Hello ".equals (name) &&" world ".equals (Password)) {RETURN Cess;} Return resulttype.login;} @ Actionannotation (ACTIONNAME = "Loginforuse.action", Results = {@Resannotation (name = resulttype.success, value = "indexp") Otary (name = resulttype.login, value = "login.jsp")})}) Public ResultType LoginForuser (Int Number, Loginpojo Loginpojo) {if ("Hello" .equals (loginpojo.getUsername ()) && "world" .equojo.getpa ssword ())) {Return Resulttype.success;} Return ResultType.login ;}}
Next, what we need to do is to allow the program to traverse all the methods in the working directory when starting, and use the Actionannotation method to find out and assemble it into ActionContext. This is the method we need to execute. In this way, when the request arrives, we can find the corresponding ActionContext according to the request address, and call the method by the reflection mechanism.
We set two servlets. One is used to perform initialization programs. One used to filter all ACTION requests
<Servlet> <Servlet> StrutsinitServlet </Servlet-Name> <Servlet-Class> com.bayern.struts.servletsInitServlet </Servlet-Class> <PAR am-name> scan_package </ Param-name> <Param-Value> Com.Bayern.Struts.one </Param-Value> </Init-Param> <Load-On-Startup> 10 </Load-Startup> > <Servlet-name> dispatcherServlet </Servlet-name> <Servlet-Class> com.bayern.Struts.one.Servlet.dispatcherservlet </servlet-mapping </servlet-mapping > <Servlet-name> DispatcherServlet </Servlet-name> <url-Pattern>*. Action </url-Pattern> </Servlet-Mapping>
DispatcherServlet implements the filtering of the ACTION request used, and enables it to execute the corresponding Action method, and make the next jump
Ublic void dopost (httpservletRequest request, httpservletResponse response) Throws service ).; ); IF (ActionContext! = Null) {ACTIONCONTEXT.SETREQUEST (Request); ActionContext.SetResponse (response); TRY {Object [] Params = DispatcherServletutututututut Il.getParams (request, actionConText.getParamStype (), ActionContext.getActionParamsName ()); Class <?> ClassStype = ACTIONCONTEXT.getClasStype (); Method Method = ClassStype.GetMethod e ()); ResultType Result = (Resulttype) METHOD.INVOKE (ACTIONCONTEXT.GetAction (), Params) ; Map<ResultType,String> results = actionContext.getResults(); if(results.containsKey(result)) { String toUrl = results.get(result); request.getRequestDispatcher(toUrl).forward(request, response); } Else {Throw New Runtimeexception ("Result Is Error! Result:" + Result);}}
好了,现在我们已经实现了最简单的strut2框架的请求转发的功能。 The function is very rough, and many cases have not considered it yet. I hope everyone will give it more pointers ~
The above is all the contents of this article. I hope everyone can like it.