Hibernate+spring+struts Extended struts_jsp Programming

Source: Internet
Author: User
Tags extend html form locale
Brief introduction:

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. At the same time we want to close the hibernate when the application closes. 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 Hibernateplugin.destroy ()");
Put hibernate cleanup code here
System.out.println ("Exiting Hibernateplugin.destroy ()");
}
This method is called at 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;
}
}

Classes that implement 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 initialization parameters to your plugin class. 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 the Struts-config.xml to notify struts there are new plugin:

<struts-config>
...
!--Message-->
<message-resources parameter= "Sample1.resources.ApplicationResources"/>

The!--Declare your plugins-->
<plug-in classname= "Com.sample.util.HibernatePlugIn"
<set-property property= "ConfigFile" value= "/hibernate.cfg.xml"
</plug-in>
</struts-config>

The 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 are:

• If your application relies on certain profiles, you can check them for availability in the plugin class and throw a servletexception if not available, so that actionservlet becomes 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 was handled

Actionservlet is the only servlet in the struts framework that handles all request. Whenever you receive a request, it will first attempt to find a sub-application for the current request. 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 Hook
if (!processpreprocess (request, response)) {
Return
}
Identify the mapping for this request
actionmapping mapping =
Processmapping (Request, response, path);
if (mapping = = null) {
Return
}
Check for no 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, mapping);
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)) {
Return
}
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, mapping);
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 get the data submitted by the user by GetParameter (), you must read the request as a inputstream and parse it yourself to get the parameter value.

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 (): Set contenttype for response by calling Response.setcontenttype (). 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 this as follows:

<controller>
<set-property property= "ContentType" value= "Text/plain"
</controller>

5. Processnocache (): If the configuration is no-cache,struts, the following three headers will be set for each response:

Requested in Struts Config.xml
Response.setheader ("Pragma", "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 to the 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. 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= "/failurepage.do"
</action>

The actionmapping element contains information such as the name of the action class and the actionform used to handle the request. 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"

Let's say 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 first checks to see if there is an object in the Org.apache.struts.action.DynaActionForm class in the request scope. 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 property of the <action> element and creates 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

With 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 allow our example to achieve 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 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, the 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,response);
}catch (Exception ex) {
}
}
return false;
}

protected void ProcessContent (HttpServletRequest request,
HttpServletResponse response) {
Check if user is requesting contactimageaction
If yes then set Image/gif as content type
if (Request.getservletpath (). Equals ("/contactimage.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 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 a text/html type of output, it is OK for you to overwrite the ProcessContent () method. 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 this text:

<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 handling 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.

Summarize

Deciding 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.

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.