|
IntegratingWithSpring
How to integrate GWT with Spring 2.0
Explained: How to Integrate GWT with Spring 2.0original by Richard Bondi These instructions are based on this GWT newsgroup post. Prerequisites: You are comfortable with using Spring without GWT. You also know the basics of how to code a GWT client making an RPC call to a GWT service. Specifically, you know that for any GWT module:
Spring's MVC works first by your browser request/url being redirected to DispatcherServlet. So let's make that happen. First, we'll configure our web.xml file to redirect all urls ending in "whatever" to go to Spring's DispatcherServlet: File: web.xml<web-app> ... <servlet-name>gwtGumby</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <servlet-mapping> <servlet-name>gwtGumby</servlet-name> <url-pattern>*.whatever</url-pattern> </servlet-mapping> ... </web-app> So far so good. Next, the DispatcherServlet will have to choose a org.springframework.web.portlet.mvc.Controller to process this request. But how does it choose? With either a BeanNameUrlHandlerMapping or a SimpleUrlHandlerMapping implementation, which you specify in an application context file. Here's an example: File: applicationContext.xml (or related file) (ignore the syntax highlighting, it's wrong)
This says that the DispatcherServlet will take any request whose url ends in "chart.whatever" and forward it to a Spring org.springframework.web.portlet.mvc.Controller whose application context id is "chartController". I'll show you the application context entries for chartController and gumbyController only at the end of this post. Before that, we have to look at these controllers. Or rather, Controller: it's actually just one Controller, which will be called with different injections for different requests. The code of this Controller class, which we've named GWTController, is shown below; here is how it works. How GWTController worksGWTController extends GWT's RemoteServiceServlet, but it also implements Spring's MVC Controller interface. When DispatcherServlet calls this Controller, it calls its handleRequest() method; handleRequest() simply calls doPost(), and returns null. What does doPost() do? Well, it is a GWT RemoteServiceServlet method that overrides javax.servlet.http.HttpServlet#doPost(). Whatever else this GWT method does, it also calls the GWT RemoteServiceServlet's processCall() method. When a GWT client makes an ajax RPC call to a GWT (RemoteServiceServlet) service, the client is sending an RPC-encoded payload. Under normal circumstances -- in other words, outside of Spring -- the service's processCall() will RPC decode the payload by calling RPCRequest rpcRequest = RPC.decode(payload, this). But that won't work now: this is the Spring Controller we've written, GWTController. Given how we have set things up in Spring, every different GWT client calll will made to the same GWT service, GWTController, instead of every client calling its matching GWT service. What to do? Answer: have Spring inject the GWT RemoteService so that we can access it from this.remoteServiceClass, and then call RPCRequest rpcRequest = RPC.decodeRequest(payload, this.remoteServiceClass). Voila: now every GWT client will have its payload decoded by the client's corresponding GWT service. Once again, so far so good. With this neat trick we've captured what some GWT Javascript client sent to us via RPC: we have our decoded payload. Now our GWT (RemoteService) service needs to process it, too. But how? We just run the same code GWT would run outside of Spring, but once again substituting the injected this.remoteServie for this. We just call: return RPC.invokeAndEncodeResponse(this.remoteService, rpcRequest.getMethod(), rpcRequest.getParameters()); And now we're done. Everything else in this class is just commentary. See for yourself: File: GWTController.java
One thing to note is that in addition to injecting a single GWT RemoteService implementation, you can inject as many non-GWT classes, services, etc etc as you wish. Even better, if you write your GWT RemoteService correctly, you can test it with stubs for all these injections -- in hosted mode, without every having to launch your web application or database! But how to do that is another post. Finally, then, here is how you inject your GWT service into the GWTController, in an application context file: File: applicationContext.xml (or related file)
That's it! Enjoy using GWT with Spring. |
Sign in to add a comment
Sounds good, except for the part where I should edit the web.xml. It is generated, and thus not editable. What is best setup here?
The simplest way =)
import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.context.ServletContextAware; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import com.google.gwt.user.server.rpc.RemoteServiceServlet; public class GWTController extends RemoteServiceServlet implements Controller, ServletContextAware { private ServletContext servletContext; public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { super.doPost(request, response); return null; } public ServletContext getServletContext() { return servletContext; } public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } }I have described how I integrated Spring without loosing "out of the box GWT works in the IDE with the Shell" in my blog.
Could be a good start for beginners...
http://adminsight.de/2008/02/14/non-invasive-gwt-and-spring-integration/
The link to the author is wrong, it should be gwttips.blogspot.com (not gwttips.blogpspot.com).
Dear all how can i configure the web.xml to load the spring context (DispatcherServlet?) in the host mode note that every time the GWT Shell create a new web.xml file without taking in consideration my xml, i need to use the host mode .. please help..
IMHO a more cleaner way: http://blog.digitalascent.com/2007/11/gwt-rpc-with-spring-2x_12.html
I found no way to edit my previous content. The link to my blog posting is:
http://pgt.de/2008/02/14/non-invasive-gwt-and-spring-integration/
to send objects over rpc which implement java.io.Serializable instead of IsSerializable? replace the return statement with the code below:
return RPC.invokeAndEncodeResponse(this.remoteService, rpcRequest.getMethod(), rpcRequest.getParameters(), rpcRequest.getSerializationPolicy());
hope this helped before you started hitting your head to walls ;) r a f t
Before you start wiring up beans as Gwt-RPC endpoints or start creating lots of RPC services, have a look at the command pattern approach described Ray Ryan at his talk. At the end, all you need is one single service, without loosing type safety.
A wrap up with link to the talk (video) and to the projects that either already where there b4 Ryans talk or were created upon the talk can be found here:
http://pgt.de/2009/09/18/best-practices-for-architecting-your-gwt-app/
There you will find a very simple and concise way to use Spring in the backend with gwt-dispatch.
Have fun!
I'm getting a NullPointerException? when calling the getServletContext(). Anyone has a clue why this happens??
Fixed my NullPointerException??. The above GWTController code should maybe be changed like I described in this post
http://blog.js-development.com/2009/09/gwt-meets-spring.html
I guess more people are having this issue.
Juri