GWT in Practice phần 9 ppt

37 302 0
GWT in Practice phần 9 ppt

Đ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

279Summary form.submit(); } }); HorizontalPanel buttons = new HorizontalPanel(); buttons.add(save); inner.add(buttons); box.setWidget(form); box.show(); } }); If you have handled file uploads from HTML or JSP pages before, this will all look fairly straightforward. We set up the <form> tag in the FormPanel object as we would for any other web application b c , and we submit the form when the Save button is clicked g . Because we aren’t going to send the user’s browser to a new page when this form is submitted, we need a way to handle the returned results. Here we’re using a Form- Handler d . One special thing to pay attention to here is that when the image is uploaded, our servlet returns text/plain as the location of the URL. Safari, however, takes the results that come back and formats them for viewing in a web page by wrapping them in a <pre> tag. Your application needs to check for this and strip it out if you just want a plain text value back from a server, as we’re doing here e . After we get the value back, we construct the real URL using the base path from the GWT application root and set it on the Book object f . With the file upload element covered, we have completed our tour of this basic CRUD application. 9.5 Summary You have already seen the basics of application construction patterns, but in this chap- ter we looked at some new issues you’ll need to address in your applications. We looked at creating a set of client-enabled DTOs and mapping them to server-side classes to make sure our service JPA beans are not serialized to our GWT client. There are several important reasons for this, as we noted: ■ serialization of JPA entities breaks down in some instances ■ you’ll often want support for PropertyChangeEvents in your client model and not on the server ■ you’ll often want to be able to share your server-side model with other server- side projects without having GWTisms attached In this chapter we used a method whereby the JPA-enabled data access beans, DAOs, and service can be used by other applications, not just our GWT web app, unlike the direct JPA example in chapter 4. In this chapter we also looked at configuring Spring within the scope of a GWT application, and using the RemoteServiceServlet as a proxy into the Spring-configured application for the client-side application. Finally, we looked at some common cases in the client application, including dealing with Submit form when clicked g 280 CHAPTER 9 Java Enterprise Reinvented many-to-many relationships in a CRUD application and handling file uploads from the client browser. In practice, this part of the Bookstore application is most useful for administrators. In the next chapter we’ll examine the customer-facing client application and look at how Java EE security constructs can affect a GWT application. 281 Building the Storefront A bookstore is one of the only pieces of evidence we have that people are still thinking. —Jerry Seinfeld In the last chapter, we looked at a basic CRUD application for a database of books. In this chapter, we’re going to take that application and turn it into the basis of an Ajax storefront that can sell the books listed in the database. While a basic database of books is OK, you’ll likely have multiple interfaces to your data—a customer- facing storefront for buying the books in the database is a good example. There are a few things we need to do to the chapter 9 application to make this happen. First, we need to secure our administration tool and create a separate ser- vice for customers. Next, we need to build a drag-and-drop system using only the GWT APIs. Also, because the storefront is the customer-facing portion of our appli- cation, it should be pretty—we’ll look at adapting a JavaScript library to create This chapter covers ■ Securing GWT applications ■ Dealing with security in the client ■ Building a drag-and-drop system 282 CHAPTER 10 Building the Storefront reflections for our cover images, as if they were sitting on a reflective surface (see fig- ure 10.3). Finally, we’ll bring it all together and construct a basic shopping cart system. 10.1 Securing GWT applications Providing security for your application you’re building is generally of critical impor- tance. In terms of GWT applications, security usually means securing the service. In the last chapter, we built a simple CRUD service for updating books in the database. Now we need to secure that service and the page using it. One of the most common ways to manage identity in the enterprise is with a Lightweight Directory Access Proto- col ( LDAP) server, so that’s what we’ll use to secure our application. In the sample application, we’ll use Apache DS, the directory server from the Apache Software Foundation. You could, of course, use Microsoft Active Directory, Fedora or Red Hat Directory Server, or Open LDAP. We’ll pass over the setup of the LDAP server—if you’re interested in such details, check out the links in table 10.1. In our web app, we have two URLs we must secure: the entry page and the service. First we need to set up the LDAP queries in the context.xml file. Listing 10.1 shows how this is done. <?xml version="1.0" encoding="UTF-8"?> <Context path=""> <Realm className="org.apache.catalina.realm.JNDIRealm" debug="99" connectionName="uid=admin,ou=system" connectionPassword="secret" connectionURL="ldap://localhost:389" roleBase="ou=roles,dc=manning,dc=com" roleName="cn" roleSearch="(uniqueMember={0})" roleSubtree="false" userSearch="(uid={0})" userPassword="userPassword" userPattern="uid={0},ou=users,dc=manning,dc=com" digest="MD5" /> </Context> Table 10.1 More information on setting up LDAP environments Environment URL ApacheDS http://www.screaming-penguin.com/node/5677 OpenLDAP http://today.java.net/pub/a/today/2005/05/31/tomcatldap.html Microsoft Active Directory http://jspwiki.org/wiki/ActiveDirectoryIntegration Listing 10.1 Adding the LDAP queries to Context.xml Specify user used to perform query b Match groupOfUniqueNames and field c Check field to determine if user is present d Specify password field e Search pattern for user’s global entry f Define encoding scheme for password 283Securing GWT applications Even if you’re unfamiliar with LDAP, this example should still be fairly straightforward. First we specify the identity of the root user we’ll use to log in to the LDAP server b . Here we’re using the default Apache DS password of secret , but you’ll want to change that. Next we specify the skeleton of a query we’ll use to identify a role node c . Roles here are LDAP objects of groupOfUniqueNames type that contain uniqueMember s that point to users in that role d . Finally we specify the query base f and the password field we’ll match e . Figure 10.1 shows the administrator role for our test application in JXplorer. TIP JXplorer is a handy Java-based LDAP client available for pretty much any platform. It’s available for free from http://www.jxplorer.org/. Now that the Realm is configured for Tomcat, we need to go back to the web.xml file and define the security settings. First, we want to secure the administration page and the administration service. We’ll do that with the <security-constraint> element. Listing 10.2 shows how we’ll configure this element. Figure 10.1 Two uniqueMember attributes point to the users defined as being in the administrator role. 284 CHAPTER 10 Building the Storefront <security-constraint> <display-name>Administration</display-name> <web-resource-collection> <web-resource-name>BookstoreService</web-resource-name> <description>The Administration Service</description> <url-pattern> com.manning.gwtip.bookstore/BookstoreService </url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> <http-method>HEAD</http-method> <http-method>PUT</http-method> <http-method>OPTIONS</http-method> <http-method>TRACE</http-method> <http-method>DELETE</http-method> </web-resource-collection> <web-resource-collection> <web-resource-name>Administration Page</web-resource-name> <description>The GWT page that hosts the app</description> <url-pattern> com.manning.gwtip.bookstore.Bookstore.jsp </url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> <http-method>HEAD</http-method> <http-method>PUT</http-method> <http-method>OPTIONS</http-method> <http-method>TRACE</http-method> <http-method>DELETE</http-method> </web-resource-collection> <auth-constraint> <description/> <role-name>administrator</role-name> </auth-constraint> </security-constraint> Here we’re specifying the service URL b and the host page URL c . You might be asking why we need to secure the host page, and not the scripts themselves. Well, obviously the host page won’t work without the service. However, you want to secure the host page so that the user is prompted to log in before this page is reached. While using HTTP Basic authentication might prompt the user when the service connection is made, this can be cumbersome, and most people are more attuned to having a customized login page in a web form these days. The Servlet specification supports this: we need to create a form that submits the user credentials to the special j_security_check URL, and an error page for when the login fails. Listing 10.3 shows the remaining bits of the web.xml deployment descriptor we must set up to facilitate this. Listing 10.2 The <security-constraint> element locks up the Administration page Define path to BookstoreService servlet b Secure HTTP calls to service c Change HTML to JSP Restrict to role 285Securing GWT applications <login-config> <auth-method>FORM</auth-method> <realm-name/> <form-login-config> <form-login-page>/login.jsp</form-login-page> <form-error-page> /login-error.jsp </form-error-page> </form-login-config> </login-config> <security-role> <description/> <role-name>administrator</role-name> </security-role> Here we’re specifying that we’re using FORM -based authentication b , as opposed to BASIC for HTTP Basic authentication. Next, we specify the two special JSP pages c d . Finally, we include a <security-role> element for each role our application needs to support. Since we only have one, we specify administrator e . Now that we have taken care of the plumbing in our web app, we need to create the special JSP pages. We’ll just look at the login.jsp page, in listing 10.4, as it demon- strates the special login form for using form-based authentication in our application. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Login Page</title> </head> <body> <h1>Login Page</h1> <form method="POST" action="<%=response.encodeURL( request.getContextPath()+ "/j_security_check")%>"> <input type="text" name="j_username" /> <br /> <input type="password" name="j_password" /> <br /> <input type="submit" /> </form> </body> </html> Here we have a very basic HTML form in a JSP page. The action is set to the special j_security_check path as mandated by the Servlet specification b . We need two Listing 10.3 The <login-config> and <security-role> elements in web.xml Listing 10.4 The login.jsp page submitting the credentials to j_security_check Specify FORM-based authentication b Specify page with login form c Error page for failed logins d Define administrator role e Set action to j_security_check URL b 286 CHAPTER 10 Building the Storefront form fields, j_username and j_password , which contain the obvious data. Now when we visit the new HTML host page, which we have turned into a JSP page, we’re first prompted with the login form based on the container-managed security settings. Fig- ure 10.2 shows this prompt in the hosted mode browser. It might seem that we’re done! The authentication prompt comes up, the user is validated against the LDAP server, and we’re passed into a working version of our CRUD application. So what’s wrong? Well, when you’re using form-based authentica- tion, the user authentication information is stored in the HTTP session, which is, by default, a cookie-based system. If the user’s browser doesn’t accept cookies, or if you’re prevented from using them by policy (such as in government agency websites), you have a problem. The session information is lost, and authentication fails when calls to the BookstoreService are made. Once again, the Servlet specification has a means of working around this: HttpServletResponse.encodeURL() . The encodeURL() method will take a path in the application and append the ses- sion identifier into the URL string so the server can determine the user authentication information from the URL and not from a cookie. The problem is that the URLs for our service are now part of the monolithic script compilation for the GWT application, so we need a way to pass in the proper service URL to our application. This is where having the host page as a JSP page comes in. First, we need to modify the host page to include the session information. Listing 10.5 demonstrates how we’ll do this, creating a JavaScript object to hold that information. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> Listing 10.5 The new JSP host page with the properly encoded service URL Figure 10.2 Bookstore.jsp is now intercepted by the login.jsp page, requiring authentication. 287Securing GWT applications <script type="text/javascript"> var services = { bookstoreService : "<%=response.encodeURL( "/com.manning.gwtip.bookstore.Bookstore/BookstoreService" ) %>" }; </script> <title></title> <meta name='gwt:module' content='com.manning.gwtip.bookstore.Bookstore'> </head> <body> <script language="javascript" src="gwt.js"></script> <iframe id="__gwt_historyFrame" style="width:0;height:0;border:0;"> </iframe> </body> </html> This is not a big change. The important thing is that once this is evaluated on the server, the path will be encoded with the session information, like this: /com.manning.gwtip.bookstore.Bookstore/BookstoreService; jsessionid=A3667E9D89E1A15B5BBD1F4F7791B395 Now we just need to get this information into our application. While it’s not designed for this purpose, there is a GWT class that will do just this. In chapter 1 you saw the Dictionary class in the internationalization package. It is designed to get internation- alization data from the host page, but we can also use it to get configuration informa- tion, such as the encoded service URL. We’ll go back to the constructor for the Controller class and change the way we assign the service endpoint. Listing 10.6 shows the new constructor. private Controller() { super(); Dictionary dict = Dictionary .getDictionary("services"); ServiceDefTarget endpoint = (ServiceDefTarget) service; endpoint.setServiceEntryPoint( dict.get("bookstoreService")); } First, we get the object we defined in the host page as services b , and then we get the value of the bookstoreService property and bind that to the endpoint of our ser- vice c . Now our service works automagically! The browser will make subsequent requests to the service using the same jsessionid value. We have now secured the BookstoreServiceServlet from unauthenticated users. Since we cannot use this system to get method-level security, we need to go back and create a customer service interface that exposes only the methods that unauthenti- cated or public users should be able to access. Listing 10.7 shows this new interface. Listing 10.6 The new Controller constructor gets the service URL from the dictionary Wrap path with session info Get Dictionary from the services object b Get value of the bookstoreService attribute c 288 CHAPTER 10 Building the Storefront package com.manning.gwtip.bookstore.client.remote; import com.google.gwt.user.client.rpc.RemoteService; import com.manning.gwtip.bookstore.client.model.Author; import com.manning.gwtip.bookstore.client.model.Book; import com.manning.gwtip.bookstore.client.model.Review; import java.util.List; public interface CustomerService extends RemoteService{ Review createReview(int bookId, Review review) throws BookstoreRemoteException; /** * @gwt.typeArgs <com.manning.gwtip.bookstore.client.model.Book> */ List findAllBooks() throws BookstoreRemoteException; /** * @gwt.typeArgs <com.manning.gwtip.bookstore.client.model.Category> */ List findAllCategories() throws BookstoreRemoteException; /** * @gwt.typeArgs <com.manning.gwtip.bookstore.client.model.Author> */ List findAllAuthors() throws BookstoreRemoteException; /** * @gwt.typeArgs <com.manning.gwtip.bookstore.client.model.Author> */ List findAuthorsByName(String firstName, String lastName) throws BookstoreRemoteException; Book findBookById(int bookId) throws BookstoreRemoteException; /** * @gwt.typeArgs <com.manning.gwtip.bookstore.client.model.Book> */ List findBooksByAuthor(int authorId) throws BookstoreRemoteException; List findBooksByCategory(String categoryName) throws BookstoreRemoteException; } Since this service is stateless and unsecured, we have nothing else to do here. The application now has two services exposed, one secured and one unsecured. We have defined the access privileges, configured our web application to enforce them, and modified our class to support cookie-less users. Listing 10.7 The CustomerService interface R euse c li ent beans, define service Define only exposed write method Define read-only methods [...]... sizes if you intend to do calculations based on them Even in GWT, you can’t completely escape testing in all browsers Summary 299 10.4 Summary In this chapter, we ran the gamut of things to consider in your GWT application: using the Java EE specification to secure your services and pages against an enterprise directory, implementing a basic shopping cart using a drag-and-drop system, and creating reflections... SourcesMouseEvents level Listing 10 .9 shows the last part of the mouse eventing for dragging Listing 10 .9 Enabling dragging in the DragAndDrop class, part 2 public void onMouseMove(Widget sender, int x, int y) { super.onMouseMove(sender, x, y); If dragging, move b to new position if(dragging != null) { DOM.setStyleAttribute(dragging.widget.getElement(), "top", Integer.toString(sender.getAbsoluteTop()... listeners Listing 10.11 shows modifications to the onMouseUp() method in the DragSupportListener inner class we’ll use to determine when a drop event has happened It’s inserted just before the revert logic Listing 10.11 Determining when a drop event has happened int top = dragging.widget.getAbsoluteTop(); int left = dragging.widget.getAbsoluteLeft(); int centerY = top + (int) ((float) dragging.widget.getOffsetHeight()... application to the shopping cart widget, outlined in red We’ll start by implementing the drag system Figure 10.3 The cover of the book being dragged to the shopping cart 290 CHAPTER 10 Building the Storefront 10.2.1 Enabling dragging Dragging is based on mouse presses and mouse movements This means, in the GWT world, using a class that implements SourcesMouseEvents Images implement this interface, and other... CometEvent { public public public public static static static static final final final final int int int int public public public public JOIN_TYPE = 0; LEAVE_TYPE = 1; IMAGE_TYPE = 2; CHAT_TYPE = 3; String username; int type; String value; long time; public CometEvent(String xml) { b Establish type using a constant 312 CHAPTER 11 Managing Application State c Document doc = XMLParser.parse(xml); Parse... what’s involved in web development, however Building up data in the client side is only a part of what you’ll need to do Another side is managing the state of the application in both the client and the server In the next chapter, we’ll look at our final application, which shows you more about using the tools GWT gives you for managing state Managing Application State This chapter covers ■ Building an... Working with the GWT history system ■ Using standard servlet state Everything is in a state of flux, including the status quo —Robert Byrne In this chapter we’re going to examine an example application we call “State of the Union.” This application demonstrates state management in a long-lived fashion, using log files to capture state on the server with the standard Java Servlet API This will be done in. .. aspect in common: you can’t escape understanding core web development principles and testing in multiple browsers and with multiple configurations Whether it’s working with security in a cookie-free environment, or overriding some browsers’ native element dragging, GWT won’t do all the work for you Recall that we said in chapter 1, GWT is a toolkit, not a framework It won’t replace good old know-how in. .. building an XML message We’re using a StringBuffer to build the message b, but you could use a true XML API to do the same thing We take care that potential special character problems are handled by the CDATA sections c Once we have this XML, we need to parse it into something a little more workable on the client side This is where the CometEvent shown in listing 11 .9 comes into play Listing 11 .9 CometEvent.java... the Comet streaming technique we introduced in chapter 5 Since conversations are taking place in real time, we want the server to push data to the client, and the Comet technique is an ideal solution We’ll use Luca Masini’s GWT Comet implementation, which we looked at in chapter 5 (from http://jroller.com/masini/entry/ updated_comet_implementation_for _gwt) , as a base and expand it into a more robust . JPA example in chapter 4. In this chapter we also looked at configuring Spring within the scope of a GWT application, and using the RemoteServiceServlet as a proxy into the Spring-configured. DOM.eventPreventDefault(event); } Listing 10.8 Enabling dragging in the DragAndDrop class, part 1 Cast to Widget to get properties b Hold original DOM settings Override native drag handling c 291 Building a drag-and-drop. we ran into while making this class support image reflection demon- strate some interesting things about images in GWT in general, which we’ll talk about after we look at the code. Listing 10.12

Ngày đăng: 14/08/2014, 11:20

Từ khóa liên quan

Mục lục

  • GWT in Practice

    • Part 3 - Fully Formed Applications

      • Java Enterprise Reinvented

        • 9.5 Summary

        • Building the Storefront

          • 10.1 Securing GWT applications

          • 10.2 Building a drag-and-drop system

            • 10.2.1 Enabling dragging

            • 10.2.2 Handling drops

            • 10.3 JSNI special effects

            • 10.4 Summary

            • Managing Application State

              • 11.1 Overview of the sample application

              • 11.2 Creating a basic messaging service

              • 11.3 Handling messages on the client and server

                • 11.3.1 Messages and CometEvents

                • 11.3.2 Streaming messages to the client

                • 11.3.3 Receiving images

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan