1. Trang chủ
  2. » Công Nghệ Thông Tin

Apress Pro Apache Struts with Ajax phần 9 docx

53 211 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 53
Dung lượng 0,91 MB

Nội dung

Now on to the implementation of JavaEdgeRequestProcessor: package com.apress.javaedge.struts.controller; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class JavaEdgeRequestProcessor extends org.apache.struts.action.RequestProcessor { private RequestProcessorHelper helper = null; public JavaEdgeRequestProcessor() { super(); helper = new RequestProcessorHelper(); } public void process( HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if(helper.checkMember(request, response)) { super.process(request, response); } } } First off, notice that this class extends org.apache.struts.action.RequestProcessor and also that you need to define a private field to hold an instance of RequestProcessorHelper, which is actually instantiated within the constructor. The important part of this class is the process() method. Within process(), you use the RequestProcessorHelper class to check for the existence of the MemberVO in the session and to create one as appropriate. The important thing to notice here is that if checkMember() returns true (that is, it executed successfully), then you allow the request chain to continue with a call to super.process(). If the checkMember() method does not succeed, most likely because the anonymous user is not in the database and there is no MemberVO in the session, then checkMember() sends the request elsewhere with this code: RequestDispatcher rd = request.getRequestDispatcher( "/WEB-INF/jsp/systemError.jsp"); rd.forward(request, response); If this code executes and the request chain is executed further by Struts, then a ServletException will be generated because when Struts comes to redirect to the view, it will find that the response has already been committed by the RequestDispatcher in CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK402 Ch11_7389_CMP2 9/25/06 9:12 PM Page 402 checkMember(). So to recap this, if you want to send the user somewhere else within the process() method, do not call super.process(); simply set the response as appropriate with RequestDispatcher and then allow the process() method to end. The code for the JavaEdgeTilesRequestProcessor is almost identical, other than the obvious difference in parent class. That is the actual code; now on to how to configure it. First off, you want to remove the <filter> and <filter-mapping> tags for MemberFilter in the web.xml file so you can test the processor. Now all you need to do is change the controller definition within struts-config.xml depending on which controller you plan to use. If you want to use tiles, then you must have the Tiles plug-in defined in the configuration file and you need to change the controller definition to <controller processorClass= "com.apress.javaedge.struts.controller.JavaEdgeTilesRequestProcessor" /> If you just want to use Struts without the Tiles framework, then use the following con- troller definition: <controller processorClass="com.apress.javaedge.struts.controller.JavaEdgeRequestProcessor" /> Now start up the application and it should work just fine—RequestProcessor now takes care of the MemberVO class in the session and not the MemberFilter class. Verifying Host Access with RequestProcessor Earlier on in the chapter we presented a solution to restrict access to the web application based on the host address. The solution used a customized base Action class to perform the check before the execute() method of an Action was run. There were two main problems with this solution. First, it required almost as much code to hook into the base Action as to perform the check manually within each Action. Second, it relied on developers to remember to derive their actions from the correct base class and to call super.execute() before any other processing. As we promised, we will be showing you a better solution to this problem; however, before we con- tinue along the road with the RequestProcessor class, we want to show you how to provide custom configuration handling for your Action classes so you can then use this knowledge to provide a much more reusable solution to the secure page problem. Creating Configuration Beans If you have read this book from the beginning, it may not have escaped your notice that in Chapter 2 we described the configuration attributes for the <action> tag and left one of them with no more than a cursory description, the className attribute. Well, now we’re going to explain exactly what it is for. Struts uses another Jakarta project called Commons Digester to handle the reading of the configuration file and its transformation into a set of Java objects. The Digester project actu- ally started out as part of Struts, but proved so useful that the Struts team separated it out into a entirely new project. CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK 403 Ch11_7389_CMP2 9/25/06 9:12 PM Page 403 The Struts team realized that extension capabilities in the world would be of no use without some way to provide additional configuration details for the extensions people were building. To this end, when integrating Digester into Struts, the Struts team left an extension point in the configuration logic so that you can replace the configuration beans with your own implementation and provide them with additional parameters. In this section, we are going to build a configuration bean that will be used in conjunction with the RequestProcessor code in the next section to provide pages that are accessible only from the host machine. Building the JavaEdgeActionMapping As of Struts 1.1, the default configuration bean for an <action> node is the ActionMapping class. By extending this class, you can provide additional configuration data to your custom RequestProcessors or actions. Okay, so that’s the theory behind it; now for an example. In this example, we are going to show you how to build a configuration bean that will allow you to specify whether or not a particular action mapping should be restricted to the local host only. The code for the actual configuration bean is fairly basic, so here it is in full: package com.apress.javaedge.struts.config; import org.apache.struts.action.ActionMapping; public class JavaEdgeActionMapping extends ActionMapping { private boolean secure = false; public JavaEdgeActionMapping() { super(); } public boolean isSecure () { return secure; } public void setSecure(boolean isSecure) { secure = isSecure; } } The JavaEdgeActionMapping class derives from org.apache.struts.action.ActionMapping, which is the default configuration bean for <action> nodes. Other than an explicit call to the parent constructor, the only thing this class has is a single boolean property, secure, with both get() and set() methods. That’s all there is to the Java code. Now all you need to do is add the appropriate configu- ration details to the struts-config.xml file. To secure the home page, you just set the className attribute to the full name of the custom configuration bean, in this case com.apress.javaedge. CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK404 Ch11_7389_CMP2 9/25/06 9:12 PM Page 404 struts.config.JavaEdgeActionMapping, and then use the <set-property> tag set the secure property to true. <action path="/homePageSetup" type="com.apress.javaedge.struts.homepage.HomePageSetupAction" unknown="true" className="com.apress.javaedge.struts.config.JavaEdgeActionMapping"> <set-property property="secure" value="false" /> <forward name="homepage.success" path="/WEB-INF/jsp/homePage.jsp" /> </action> Now when you request the home page from a remote machine, what happens? It is still displayed. At this point, all you have done is provide the configuration data, nothing more. In the next section, we are going to revisit the RequestProcessor classes, this time to implement the processActionPerform() method to make use of this additional configuration data. Revisiting RequestProcessor At this point, we have taken you through the basic mechanics of extending the RequestProcessor class and through building custom configuration beans. In this section, we are going to combine that knowledge to build a much more comprehensive solution to the secure page problem that was highlighted in the “Extending Action and ActionForm” section. To recap the last section, we showed you how to build a custom configuration bean that allows you to specify whether or not a page should be restricted to being viewed on the host machine, by setting the secure property accordingly. Now you need to implement the code within your RequestProcessor to read this configuration data and act appropriately. You already have the basics of the RequestProcessor classes in place for both Tiles-based and non–Tiles-based applications. All you need to do is extend these classes to provide the desired features. To start, implement the checkHost() method in the RequestProcessorHelper class: public boolean checkHost( HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException, ServletException { if (mapping instanceof JavaEdgeActionMapping) { JavaEdgeActionMapping jeMapping = (JavaEdgeActionMapping) mapping; if (jeMapping.getSecure()) { String hostAddress = request.getRemoteHost(); if (!hostAddress.equals("localhost")) { RequestDispatcher rd = CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK 405 Ch11_7389_CMP2 9/25/06 9:12 PM Page 405 request.getRequestDispatcher( "/WEB-INF/jsp/accessDenied.jsp"); rd.forward(request, response); // Secure action and different host. // Deny access. return false; } else { // Host address matches, allow access. return true; } } else { // Not a secure action, allow access. return true; } } else { // Not a secure action, allow access. return true; } } This method is quite complex, so we’ll take you through it step by step. First off is the list of arguments the method accepts and its return type: public boolean checkHost( HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) { You define the checkHost() method as returning a boolean, which will be true if the users are allowed access to the resource and false if they are not. In this way, you indicate when calling the method from your custom RequestProcessor class whether to allow Struts to carry on processing or not. As you can see, you include HttpServletRequest and HttpServletResponse arguments, along with an ActionMapping argument. If you recall from the previous section, “Creating Configu- ration Beans,” ActionMapping is the default configuration class for all action mappings in the Struts framework. As such, Struts will pass this argument to the RequestProcessor; it is up to you to check it to see if it is actually your custom configuration bean, which is exactly what occurs as the first line of code for this method. if (mapping instanceof JavaEdgeActionMapping) { JavaEdgeActionMapping jeMapping = (JavaEdgeActionMapping) mapping; } else { // Not a secure action, allow access. return true; } CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK406 Ch11_7389_CMP2 9/25/06 9:12 PM Page 406 If ActionMapping is an instance of JavaEdgeActionMapping, then you cast it to that type, ready for additional checks; if not, then you assume that the resource the user is requesting is not intended to be secure, so you return true, indicating that the user is allowed access. If you are dealing with an instance of JavaEdgeActionMapping, then you first check the return value of getSecure(). if (jeMapping.getSecure()) { String hostAddress = request.getRemoteHost(); if (!hostAddress.equals("localhost")) { RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/jsp/accessDenied.jsp"); rd.forward(request, response); // Secure action and different host. // Deny access. return false; } else { // Host address matches, allow access. return true; } } else { // Not a secure action, allow access. return true; } If getSecure() returns false, then although the configuration bean has been set to JavaEdgeActionMapping, the secure property is false, and this resource is intended for public access. If, however, getSecure() returns true, then you perform further checks to see if the host name of the requesting user is localhost. If the user is requesting from localhost, then you return true to allow that user access; otherwise, you forward the request to the accessDenied.jsp page and return false. As far as explanations go, that was pretty intense, so just to recap: checkMember() will be passed an instance of ActionMapping. If this ActionMapping instance is in fact an instance of JavaEdgeActionMapping, then the method will perform further checks on the request; other- wise, the method returns true. If the ActionMapping argument is a JavaEdgeActionMapping instance, then the method checks to see if the getSecure() method returns true or false. If getSecure() is false, then the user is cleared to view the resource and the method returns true. If getSecure() is true, then checkMember() checks the host address of the requesting user. If the user is requesting from localhost, then they are allowed access and checkMember() returns true; otherwise the request is forwarded elsewhere and checkMember() returns false. Now all that is left for us to do is hook into the appropriate method in the JavaEdgeRequestProcessor and JavaEdgeTilesRequestProcessor classes. If you use forwards or includes in your application as well as normal actions, then you will actually want to hook into three methods in the RequestProcessor: processActionPerform(), processForward(), and processInclude(); since processActionPerform is only called for actions, includes and CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK 407 Ch11_7389_CMP2 9/25/06 9:12 PM Page 407 forwards have their own methods to hook into. Here is the code for processForward() and processInclude() taken from JavaEdgeRequestProcessor: protected boolean processForward( HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException, ServletException { if (helper.checkHost(request, response, mapping)) { return super.processForward(request, response, mapping); } else { return false; } } protected boolean processInclude( HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException, ServletException { if (helper.checkHost(request, response, mapping)) { return super.processInclude(request, response, mapping); } else { return false; } } As you can see, the methods are very similar, only differing in which method of the super- class they call internally. The logic here is quite simple. If checkHost() returns true, then the user is allowed access to the resource, and the method defers control to the superclass; this allows Struts to process as normal and will return the value of the corresponding method of the superclass. However, if checkHost() returns false, then the method returns false to stop Struts from performing any more processing and causing an error, since the response has already been committed by the call to RequestDispatcher.forward() in the checkHost() method. The code for processActionPerform() does not differ that much: protected ActionForward processActionPerform( HttpServletRequest request, HttpServletResponse response, Action action, ActionForm form, ActionMapping mapping) throws IOException, ServletException { if (helper.checkHost(request, response, mapping)) { CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK408 Ch11_7389_CMP2 9/25/06 9:12 PM Page 408 return super.processActionPerform( request, response, action, form, mapping); } else { return null; } } Aside from the noticeable increase in method arguments, the only difference here is that the method returns ActionForward instead of boolean. So, as with the previous method, if the user is allowed to view the resource, then control is passed to the superclass and the appropri- ate result is returned from the method, resulting in Struts carrying on processing as normal. However, if the user isn’t allowed to view the resource, then the method returns null, which will instruct Struts to stop any more processing, thus avoiding any errors. As you can see from the code examples, you don’t actually need very much code to build your own RequestProcessor and custom configuration beans. If you follow the patterns for managing the response, then you shouldn’t come across any errors in which Struts tries to manipulate a response that you have already committed earlier on. Just remember in this situ- ation that if you send the request elsewhere, then you have to instruct Struts to stop processing using the methods described. One point of interest before we move on to the recap is that the process() method executes before the processActionPerform, processForward(), and processInclude() methods. In fact, the process() method is responsible for calling those methods. So in the case of the JavaEdge application, the session will be checked for the MemberVO and have one added if appropriate well before the user’s right to access the resource is verified. You may find that this could have an impact on your application, in which case you can move any logic from process() into processActionPerform(), processForward(), and processInclude(). The last few sections have given you an in-depth look at how to extend the Struts RequestProcessor class and how to provide additional configuration data to your custom RequestProcessor classes using custom configuration beans. The next section describes the fourth and final method of extending the Struts framework. Building a Plug-In Perhaps the most widely known method of extension in Struts is the plug-in method. In fact, many of the additional features for Struts, such as Validator and the Tiles framework, use plug- ins to add their functionality to the framework. Building a plug-in differs from building a RequestProcessor in that you are not intercepting each individual request; instead, you are hooking into the framework as it loads. Generally, plug-ins are used to load in some kind of application-specific data or to perform startup actions that are needed to ensure that the application will run correctly. We have also found that using plug-ins is an ideal way to run some background processes within the context of the servlet container, without having to fudge some kind of solution in which you have a scheduled task on the OS that requests a specific URL at a specific interval. CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK 409 Ch11_7389_CMP2 9/25/06 9:12 PM Page 409 In this section, we are going to take you through the entire process of building a plug-in and configuring it within the Struts framework. The plug-in we are going to show you how to build will send out an e-mail newsletter of the top stories to all members in the JavaEdge application at a set interval. Newsletter Service Basics Before we get to the details of the actual plug-in implementation, we want to discuss the exact behavior of the Newsletter Service and look at the classes that actually implement the service before demonstrating how to hook these classes into Struts with a custom plug-in implemen- tation. The basic aim of the Newsletter Service is to send the list of top stories, via e-mail, to each member registered in the JavaEdge database. The logic for loading the top stories from the database is already built and is explained in Chapter 2. On top of this, we want to make the interval between sending the e-mails, the address of the SMTP server used, and the sender address of the e-mail externally configurable so they can be changed without having to go back to the code. Thankfully, the Struts plug-in model makes it quite easy for you to create the implementa- tion that you want. As you will see, building the logic for the actual Newsletter Service is much more complex than building the plug-in. NewsletterManager When you are building a plug-in, you should really consider refactoring the logic that plug-in is intended to perform into a separate class. If you have to use the logic elsewhere or for some reason you want to move from Struts to another technology, then you will have a much easier time of it. For the Newsletter Service, you create the NewsletterManager class to take care of the newsletter construction and the sending of e-mails. The code for NewsletterManager is quite long, so we will go through each method sepa- rately, instead of giving one big block of code and attempting to explain it in one go. The basic class looks like this: public class NewsletterManager { private static Log log = ServiceLocator.getInstance().getLog(NewsletterManager.class); private String _smtpServer = ""; private String _fromAddress = ""; public NewsletterManager(String smtpServer, String fromAddress) { _smtpServer = smtpServer; _fromAddress = fromAddress; } } Notice that you define a Commons Log instance so that you can log any errors that occur when trying to build or send the mail. Also note that there are two private fields to hold the address of the SMTP server and the e-mail address to use as the sender address for the outgoing CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK410 Ch11_7389_CMP2 9/25/06 9:12 PM Page 410 mail. The class has a single constructor that is used to pass in values for the _smtpServer and _fromAddress fields. The class contains one public method, sendNewsletter(), which when called by the client application will build the newsletter and send it via e-mail to the JavaEdge members: public void sendNewsletter() throws ApplicationException { String mailContent = getNewsletterContent(); Session mailSession = getMailSession(); Collection recipients = loadRecipients(); Message msg = new MimeMessage(mailSession); try { // From address Address fromAddress = new InternetAddress(_fromAddress); msg.setFrom(fromAddress); // Subject line msg.setSubject("JavaEdge Newsletter"); // Body content msg.setText(mailContent); // Recipient addresses Iterator iter = recipients.iterator(); while(iter.hasNext()) { MemberVO member = (MemberVO)iter.next(); if(member.getEmail().length() > 0) { Address bccAddress = new InternetAddress(member.getEmail()); msg.addRecipient(Message.RecipientType.BCC, bccAddress); } } // Send. Transport.send(msg); } catch (AddressException e) { log.error("AddressException in NewsletterManager", e); throw new ApplicationException("AddressException in NewsletterManager", e); } catch (MessagingException e) { log.error("MessagingException in NewsletterManager", e); throw new ApplicationException("MessagingException in NewsletterManager", e); } } CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK 411 Ch11_7389_CMP2 9/25/06 9:12 PM Page 411 [...]... Setting this up within a Struts application will be left for you as an exercise to complete on your own You need to register the action in the struts- config.xml file and set it up like you would with any other struts JSP and action classes Run it, and see what you get 431 Ch12_73 89_ CMP2 432 9/ 29/ 06 9: 31 AM Page 432 CHAPTER 12 ■ STRUTS AND AJAX Summary Ajax is a cool new technology and is probably here... XMLHttpRequest object Enough fun and games, let’s look at an example of Ajax using Struts and see how the XMLHttpRequest object is really used 425 Ch12_73 89_ CMP2 426 9/ 29/ 06 9: 31 AM Page 426 CHAPTER 12 ■ STRUTS AND AJAX Ajax and Struts in Action In this section we will build an example of a simple Struts application that uses Ajax This application is similar to the Google Suggest feature, which offers... org .apache. struts. action.ActionForward; org .apache. struts. action.ActionMapping; org .apache. struts. action.*; /** * Struts action class */ public class GetCitiesNamesAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response) 4 29 Ch12_73 89_ CMP2 430 9/ 29/ 06 9: 31 AM Page 430 CHAPTER 12 ■ STRUTS AND AJAX throws Exception { CitiesDAO... RequestProcessor classes and how they can be used to hook into the request processing flow for Struts We combined the knowledge of RequestProcessors gained earlier in the chapter with that of building custom configuration beans in order to provide a much more elegant solution to the problem of secure pages From this, we have 4 19 Ch11_73 89_ CMP2 420 9/ 25/06 9: 12 PM Page 420 CHAPTER 11 ■ EXTENDING THE STRUTS. .. which Ajax is being used today, just to give you a flavor of what Ajax can really do 421 Ch12_73 89_ CMP2 422 9/ 29/ 06 9: 31 AM Page 422 CHAPTER 12 ■ STRUTS AND AJAX Ajax on Google Of course, as one might expect, Google is one of the biggest users of the new Ajax technologies Google Gmail, Google Calendar, and the Google Personalized Home page are some prime examples of web applications that implement Ajax. .. org .apache. commons.logging.Log; org .apache. struts. action.ActionServlet; org .apache. struts. action.PlugIn; org .apache. struts. config.ModuleConfig; org .apache. struts. config.PlugInConfig; import com .apress. javaedge.common.ServiceLocator; public class NewsletterPlugIn implements PlugIn { private static Log log = Ch11_73 89_ CMP2 9/ 25/06 9: 12 PM Page 417 CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK ServiceLocator.getInstance().getLog(NewsletterPlugIn.class);... request Any automated processes such as cleanup operations, marketing, or auditing that you would normally do via some kind of OS scheduled task can now be done using a Struts plug-in Ch12_73 89_ CMP2 9/ 29/ 06 9: 31 AM CHAPTER Page 421 12 ■■■ Struts and Ajax A jax, or Asynchronous JavaScript and XML, was introduced in 2005 by Jesse James Garrett, sometimes referred to as the “father of Ajax. ” Ajax is not a single... lead to performance and other issues Use Ajax only when traditional JavaScript widgets don’t suffice, and when you have to do data manipulations involving round trips to the server Here is a good blog you can read to find out when not to use Ajax: http://alexbosworth backpackit.com/pub/67688 Ch12_73 89_ CMP2 9/ 29/ 06 9: 31 AM Page 423 CHAPTER 12 ■ STRUTS AND AJAX Ajax and Web 2.0 The Internet has grown... use the configuration properties to set the values without having to change the code As you can see, configuring the plug-in is very easy, and you are free to configure as many plug-ins as you like within your application... standard is finalized and then adopted, you need to deal with cross-browser issues when programming in Ajax Also, don’t abuse the use of Ajax For example, persist only useful data in the background; don’t use it to skip confirmation dialog boxes, and so on Be wise about when you really need the power of Ajax Have fun with it! AppA_73 89_ CMP2 9/ 25/06 9: 14 PM Page 433 APPENDIX A ■■■ JavaEdge Setup and Installation . THE STRUTS FRAMEWORK 4 09 Ch11_73 89_ CMP2 9/ 25/06 9: 12 PM Page 4 09 In this section, we are going to take you through the entire process of building a plug-in and configuring it within the Struts. org .apache. commons.logging.Log; import org .apache. struts. action.ActionServlet; import org .apache. struts. action.PlugIn; import org .apache. struts. config.ModuleConfig; import org .apache. struts. config.PlugInConfig; import com .apress. javaedge.common.ServiceLocator; public. solution to the problem of secure pages. From this, we have CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK 4 19 Ch11_73 89_ CMP2 9/ 25/06 9: 12 PM Page 4 19 CHAPTER 11 ■ EXTENDING THE STRUTS FRAMEWORK420 demonstrated

Ngày đăng: 12/08/2014, 22:22