Project I see a lot of projects where developers implement their own MVC framework, not because they want to do something different from struts, but because they don't realize how to extend struts. Developing your own MVC framework can gain full control, but it also means that you need a lot of resources to implement it (human resources), which is sometimes impossible under tight schedules. Struts is not only a powerful framework, but it is also extensible. You can extend struts in three different ways. 1. PlugIn: If you want to do some business logic when application startup or shutdown, create your own PlugIn class. 2. Requestprocessor: If you want to do some business logic at some point in the process of processing a request, create your own Requestprocessor class. For example, before each request is executed, you can extend the requestprocessor to check whether the user has logged in and whether he has permission to perform a specific action. 3. Actionservlet: If you want to do some business logic when application startup and shutdown, and when the request is processed, you can also expand the Actionservlet class. But you should use Actionservlet when plugin and requestprocessor are unable to solve your needs. In this article, we'll use an example of struts application to demonstrate how to extend struts using these three ways. The code for the sample program can be downloaded from the Http://www.onjava.com/onjava/2004/11/10/examples/sample1.zip. Two examples of successful extension struts are the validation and tiles framework of struts itself. Let's say you're already familiar with the struts framework and know how to use it to create a simple application. If you would like to know more about struts, please refer to the official home page. PlugIn PlugIn is an interface where you can create a class that implements the interface and do something when application startup or shutdown. For example, I created a Web application that uses hibernate as a persistence layer, and I want to initialize hibernate when the application is started, so that when my Web application receives the first request, Hibernate is already configured and available. And we want to be application off.The time to close hibernate. We can use a hibernate PlugIn to achieve this requirement, through the following two steps: 1, create a class to implement the PlugIn interface: public class Hibernateplugin implements plugin{private String ConfigFile; This method is called at application Shutdown Time public void Destroy () {System.out.println ("Entering Hibern Ateplugin.destroy () "); Put hibernate cleanup The code here System.out.println ("Exiting Hibernateplugin.destroy ()"); //this method would be called in application startup time public void init (Actionservlet actionservlet, moduleconfig Config) throws servletexception {System.out.println ("Entering Hibernateplugin.init ()"); System.out.println ("Value of init parameter" + getconfigfile ()); System.out.println ("Exiting Hibernateplugin.init ()"); Public String Getconfigfile () {return name; public void Setconfigfile (string string) {configfile = string; The class that implements the plugin interface must complete two methods: Init () and Destroy (). When application startup, the Init () method is invoked, and the Destroy () method is invoked when shutdown. Struts also allows you to pass the plugin classThe recursive initialization parameter. In order to pass parameters, you must create a JavaBean setter method for each parameter in the plugin class. In our Hibernateplugin class, I'm going to pass the name of ConfigFile as a parameter instead of hard-coded into the program. 2, add the following code in Struts-config.xml to announce that struts has a new plugin: <struts-config> ... !--message--> <message-resources parameter= "sample1.resources.ApplicationResources"/>!--Declare your Plugins--> <plug-in classname= "Com.sample.util.HibernatePlugIn" "<set-property property=" ConfigFile "value=" Hibernate.cfg.xml the/> </plug-in> </struts-config> property ClassName is the fully qualified name of the class that implements the plugin interface. For each initialization parameter, you can use the <set-property> element to pass parameters. In our example, I'm going to pass the name of the config file, so I use a <set-property> with a path to the configuration file. The tiles and validator frameworks of struts use plugin to read configuration files for initialization. The other two things plugin can do for you: • If your application depends on certain profiles, then you can check if they are available in the plugin class and throw a servletexception if not available. This allows actionservlet to become unusable. · The init () method of the plugin interface is the last chance you can change moduleconfig, Moduleconfig is a set of static configuration information that describes the Struts module. Struts will release moduleconfig after all plugin have been processed. How the request is handled Actionservlet is the only servlet in the Struts framework, which handles all request. Whenever a request is received, it will first attempt to req the currentUest looking for a sub-application. Once a sub-application is found, Actionservlet creates a Requestprocessor object for that Sub-application and invokes the process () of the object. Method and the HttpServletRequest and HttpServletResponse objects are passed in. Requestprocessor.process () is where most of the request is processed. The process () method is implemented using the template method pattern, which has a number of independent methods to perform each step of the request processing that will be invoked sequentially in the process method. For example, there will be a separate way to find the Actionform class for the current request, a method to check whether the current user has the necessary permissions to perform the action mapping. These give us a great deal of flexibility. There is a Requestprocessor class in the published struts package that provides the default implementation for each step of the request processing. This means that you can simply rewrite the methods you are interested in and use the default implementations. For example, by default, struts calls Request.isuserinrole () to check whether the user has permission to execute the current actionmapping; If you want to do this by querying the database, all you have to do is rewrite the Processroles () method, Returns TRUE or false by querying whether the user has the necessary permissions. First we'll see how the process () method is implemented by default, and then I'll explain each of the methods in the default Requestprocessor class in detail so you can decide which part you want to change. public void process (HttpServletRequest request,httpservletresponse response) throws IOException, servletexception {// Wrap multipart requests with a special wrapper request = Processmultipart (request); Identify the path component we//use to select a mapping String path = procEsspath (request, response); if (path = = null) {return; } if (log.isdebugenabled ()) {Log.debug ("processing a '" + request.getmethod () + "' for path '" + Path + ""); }//Select a Locale for the current user if requested Processlocale (request, response); Set the content type and no-caching headers//If requested processcontent (request, response); Processnocache (request, response); General purpose preprocessing Hooks if (!processpreprocess (request, Response)) {return; }//Identify the mapping for this request actionmapping mapping = processmapping (request, response, path); if (mapping = = null) {return; }//Check for the any role required to perform this action if (!processroles (request, response, mapping)) {return; }//Process any actionform beans related to this request actionform form = Processactionform (request, Response, Mappin g); Processpopulate (Request, response, form, mapping); if (!processvalidate (Request, RESPONSE, form, mapping)) {return; //Process A forward or include specified by this mapping if (!processforward (request, response, mapping)) {Retur N } if (!processinclude (request, response, mapping)) {return; //Create or acquire the action instance to//process this request action action = processactioncreate (Request, response, mapping); if (action = null) {return; }//Call the Action instance itself actionforward forward = processactionperform (request, response,action, form, Mapp ing); Process The returned Actionforward instance processforwardconfig (request, response, forward); 1, Processmutipart (): In this method, struts will read the request to check whether the request's contenttype is multipart/form-data. If so, the request will be parsed and packaged into HttpServletRequest. When you create an HTML form to submit data, the ContentType defaults to the request is application/x-www-form-urlencoded. But if your form uses the file type input control to allow users to upload files, you must change the contenttype to Multipart/form-data. If this is the case, you can no longer use getparameter () to obtain the data submitted by the user; You must use the request as a InputstreaM to read and parse it itself to get the value of the parameter. 2, Processpath (): In this method, struts will read the URI of the request to determine the path element, which is used to get the actionmappint element. 3, Processlocale (): In this method, struts will obtain locale for the current request, if configured, You can also save this object as the value of the Org.apache.struts.action.LOCALE property in HttpSession. As a side effect of this method, HttpSession will be created, and if you do not want to create, you can set the Locale property to False in Controllerconfig, in Struts-config.xml as follows: <controller> <set-property property= "locale" value= "false"/> </controller> 4, ProcessContent (): by calling Response.setconte Nttype () to set the ContentType for the response. This method will first attempt to get ContentType from the Struts-config.xml configuration. By default, text/html is used. If you want to overwrite it, you can do it like this: <controller> <set-property property= "ContentType" value= "Text/plain"/> </controller> 5, Processnoca Che (): If the configuration is no-cache,struts, the following three headers:requested in Struts Config.xml response.setheader ("Pragma") will be set for each response. No-cache "); Response.setheader ("Cache-control", "No-cache"); Response.setdateheader ("Expires", 1); If you want to set the No-cache header, add the following information in Struts-config.xml: <controller> <set-property property= "NoCache" value= "true"/> </controller> 6, processpreprocess (): This method provides a hook for preprocessing, which can be overridden in subclasses. Its default implementation does nothing, always returns TRUE. Returning false will terminate the processing of the current request. 7, Processmapping (): This method will use the path information to get a Actionmapping object. That is, the <action> element in the Struts-config.xml file: <action path= "/newcontact" type= "Com.sample.NewContactAction" Name= " Newcontactform "scope=" request "> <forward name=" sucess "path="/sucesspage.do "/>" <forward name= "Failure" path= "/failur" The epage.do "/> </action> actionmapping element contains the name of the action class and the actionform that handles the request use, and so on. It also contains actionforwards information for the current actionmapping configuration. 8, Processroles (): Struts Web Application provides a licensing scheme. That is, once a user has logged into the container, the Processroles () method of struts will check to see if he has the necessary role to run a given actionmapping by calling Request.isuserinrole (). <action path= "/adduser" roles= "Administrator"/> assume that you have a adduseraction and you just want the administrator to be able to add new user. All you have to do is add a role attribute to your adduseraction element, the value of this attribute is the administrator. This way, before running Adduseraction, this method ensures that the user has a ADMINISTRAOTR role. 9, Processactionform (): Each actionmapping is a corresponding Actionform class. When struts handles a actionmapping, it will find the name of the corresponding Actionform class from the <action> element's Name property. <form-bean name= "Newcontactform" type= "Org.apache.struts.action.DynaActionForm" "<form-property name=" FirstName "type=" Java.lang.String "/> <form-property name=" LastName "type=" java.lang.String "/>" </form-bean> in our case, it will be first in the request scope Check if there is an object in the Org.apache.struts.action.DynaActionForm class. If it does, it will use this object, and if not, it will create a new object and set it in Request scope. 10. Processpopulate (): In this method, struts will assemble actionform instance variables with matching request parameters. 11. Processvalidate (): Struts will call the Validate method of your Actionform class. If you return actionerrors from validate (), it redirects user to the page specified by the input property of the <action> element. 12, Processforward () and Processinclude (): In these methods, struts will check the forward or include attributes of the <action> element, if found, Forward or include requests will be placed on the configured page. <action forward= "/login.jsp" path= "/logininput"/> <action include= "/login.jsp" path= "/logininput"/> You can guess the difference from the names of these methods: Processforward () eventually calls Requestdispatcher.forward (), and Processinclude () Call Requestdispatcher.include (). If you configure both the forward and include attributes, it will always call forward because forward is processed first. 13, Processactioncreate (): This method obtains the name of the action class from the type attribute of the <action> element andCreates an instance that returns it. In our example, it will create an instance of the Com.sample.NewContactAction class. 14, Processactionperform (): This method calls the Excute () method of your action class, and your business logic is in the Excute method. 15, Processforwardconfig (): The Excute () method of your action class will return a Actionforward object that will indicate which page is displayed to the user. Therefore, struts will create a requestdispatcher for that page and Invoke Requestdispatcher.forward (). The above list describes the work that the default Requestprocessor implementation does each step in processing the request, and the order in which it is executed. As you can see, requestprocessor is very flexible and allows you to configure it by setting the properties of the <controller> element. For example, if your application is prepared to generate XML content instead of HTML, you can notify struts by setting the attributes of the controller element. Create your own requestprocessor through the above, we learned how the default implementation of Requestprocessor works. Now we're going to show you an example of how to customize your own requestprocessor. To showcase the creation of user-tailored requestprocessor, we will let our example implement the following two business requirements: • We want to create a contactimageaction class that will generate pictures instead of normal HTML pages. • Before each request is processed, We all want to check the username attribute in the session to determine if the user has logged in. If that attribute is not found, we will redirect the user to the landing page. We will meet these business requirements in two steps. 1, create your customrequestprocessor class, it will inherit from the Requestprocessor class, as follows: public class Customrequestprocessor extends Requestprocessor {protected Boolean processpreprocess (HttpServletRequest request,httpservletresponse responSE) {HttpSession session = Request.getsession (false); If user is trying to access login page//Then don ' t check if (Request.getservletpath (). Equals ("/logininput.do") || Request.getservletpath (). Equals ("/login.do")) return true; Check If UserName is there to session. If So, it means user has allready logged in if (session!= null && session.getattribute ("userName")!= null) return true; else{try{//if No redirect user to login Page request.getrequestdispatcher ("/login.jsp"). Forward (Request,re Sponse); }catch (Exception ex) {}} return false; } protected void ProcessContent (HttpServletRequest request, httpservletresponse response) {//check If user is Reque Sting contactimageaction//If yes then set Image/gif as content type if (Request.getservletpath (). Equals ("/contactima Ge.do ")) {Response.setcontenttype (" image/gif "); Return Super.processcontent (request, response); } } In the Processpreprocess method of the Customrequestprocessor class, we check the username attribute of the session and redirect the user to the landing page if it is not found. For the need to generate pictures as output, we must override the ProcessContent method to first check whether the request is a/contactimage path. If so, we will set the ContentType to Image/gif; otherwise set to text/html. 2. Add the following text after the <action-mappint> element of your struts-config.xml file, telling struts that customrequestprocessor should be used as a Requestprocessor class: <controller> <set-property property= "Processorclass" value= "Com.sample.util.CustomRequestProcessor"/> </ controller> Note that when you have very few action classes that need to generate text/html type of output, you can override the ProcessContent () method is OK. If this is not the case, you should create a child application of struts to process the action of the request generation picture and set the ContentType to Image/gif. The tiles frame of struts is to decorate the output of struts with its own requestprocessor. Actionservlet If you look at the web.xml of your struts Web application, you will see text like this: <web-app > <servlet> <servlet-name> action= </servlet-name> Servlet-class>org.apache.struts.action.actionservlet </servlet-class>!--All your init-params go here--> </servlet> <servlet-mapping> <servlet-name> Action </servlet-name> <url-pattern> *.do </url-pattern> </servlet-mapping> </web-aPP > This means that Actionservlet is responsible for all of your struts requests. You can create a actionservlet subclass, when the application starts, shuts down, and does something specific for each request. But before inheriting the Actionservlet class, you should try to create a plugin or requestprocessor to solve your problem. Before Servlet1.1, the tiles framework is based on Actionservlet to decorate the generated response. But after 1.1, it started using the Tilesrequestprocessor class. Summarizing the decision to develop your own MVC framework is a very big decision, and you have to consider the time and resources spent developing and maintaining the framework code. Struts is a very powerful and stable framework that you can modify to meet the vast majority of your business needs. But on the other hand, don't make a hasty decision to extend struts. If you write some low performance code in Requestprocessor, it will be executed on each request, thus reducing the efficiency of your entire application. And there are situations where it's better to develop your own MVC framework than to extend struts.
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.