Spring 3.0 with Google App Engine

For one of my final classes as an undergraduate student at Georgia Tech I’m working on a Java based webapp to be hosted in the cloud. I’ve chosen Google App Engine for its Java support and the fact that I can use if for free.  The app will make use of the Spring framework which just released version 3.0 and use JSP and JSTL for the presentation layer.  I’ve decided to post a little tutorial on getting up an running with Google App Engine (GAE), Spring 3.0, and Eclipse so that hopefully I (and anyone else that reads this) can avoid some of the pitfalls I ran into on the initial project setup.

Setting up the project in Eclipse

  1. First, you will need to set up the GAE plugin for Eclipse.  Google provides easy instructions for this here.  At the time of this posting, the current version of the SDK should be 1.3.1.
  2. Create a new project in your Eclipse workspace of type Google Web Application Project
    Choose "Web Application Project" from the Google Folder in the New Project Wizard

    The poject type is under the "Google" folder

    Do not use the Google Web Tool Kit and be sure to use the latest version of the SDK

    Enter the project settings

    You should now have a project with the following setup:

    These are the files the plugin sets up for you automatically

    Inital project structure

    The project is now set up, you can run the server by clicking the “Debug” button in Eclipse and visiting localhost:8888 in your browser.

  3. Before we start setting up Spring, let’s clean out some of the things in the project we won’t need.  You can delete the GAESpringProjectServlet.java file and change the file war/WEB-INF/web.xml to:
    <?xml version="1.0" encoding="utf-8"?>
    
    <web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    
    </web-app>
  4. Now that the project is clean we can add in the libraries needed by the Spring framework. Download Spring from the springsource website.  You will also need commons-logging.jar and xalan.jar.  We don’t need to worry about the JSTL jars because GAE includes them for you. Add the following into the war/WEB-INF/lib folder for your project and add them to the build path (the file names have the version information left off, it should be “-3.0.0.RELEASE” for the spring jars):
    1. org.springframework.asm.jar
    2. org.springframework.beans.jar
    3. org.springframework.context.jar
    4. org.springframework.core.jar
    5. org.springframework.expression.jar
    6. org.springframework.web.servlet.jar
    7. org.springframework.web.jar
    8. commons-logging.jar
    9. xalan.jar
  5. Now it’s time to set up the configuration files for Spring.  First war/WEB-INF/web.xml:
    <?xml version="1.0" encoding="utf-8"?>
    
    <web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    
    	<servlet>
    		<servlet-name>dispatcher</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    		<load-on-startup>1</load-on-startup>
    	</servlet>
    
    	<servlet-mapping>
    		<servlet-name>dispatcher</servlet-name>
    		<url-pattern>/a/*</url-pattern>
    	</servlet-mapping>
    
    </web-app>

    The dispatcher servlet handles all user requests and passes them along to the correct controller. The url mapping is to anything under the /a/ directory because of a bug with GAE.  The development server will not accept the url pattern of /* so in development you must add a prefix.  You can remove the /a before you deploy to a production GAE instance.

  6. Now create the file war/WEB-INF/dispatcher-servlet.xml and add the contents:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
     xmlns:context="http://www.springframework.org/schema/context"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
     <context:component-scan base-package="com.acrhodes.gaespringproject.controllers" />
    
     <bean id="viewResolver"
     class="org.springframework.web.servlet.view.InternalResourceViewResolver"
     p:prefix="/WEB-INF/views/" p:suffix=".jsp" >
     <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
     </bean>
    
    </beans>

    This sets several things up for us.  First, the context:component-scan tag tell spring to search the “com.acrhodes.gaespringproject.controllers” package for classes marked with the @Controller annotation so that we don’t have to set them up explicitly in the xml.  The viewResolver bean sets up our views to use JSTL and to return the jsp /WEB-INF/views/home/home.jsp when the view name “home/home” is given.

  7. Our final configuration file will tell Spring that we are using annotations to manage all of the bean mapping.  Add the file war/WEB-INF/applicationContext.xml with the contents:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    
    http://www.springframework.org/schema/context
    
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
    <context:annotation-config/>
    
    </beans>
  8. Now we are ready to start developing our application.  Create a new package “com.acrhodes.gaespringapplication.controllers” that will house all of the controller classes and create a new HelloController class in it.  HelloController will be a simple login/logout service using the Google User Service.  Add the following code to the class:
    @Controller
    @RequestMapping("/hello")
    public class HelloController {
    
        private UserService userService = UserServiceFactory.getUserService();
    
        @RequestMapping(method = RequestMethod.GET)
        public String hello(HttpServletRequest request, ModelMap model)
        {
            String url = request.getRequestURI();
            String message;
    
            if(request.getUserPrincipal() != null)
            {
                message = new StringBuilder()
                .append("Hello, ")
                .append(request.getUserPrincipal().getName())
                .append("! You can <a href=\"")
                .append(userService.createLogoutURL(url))
                .append("\">Sign Out</a>.").toString();
            }else{
                message = new StringBuilder()
                .append("Please ")
                .append("<a href=\"")
                .append(userService.createLoginURL(url))
                .append("\">Sign In</a>.").toString();
            }
    
            model.addAttribute("message", message);
    
            return "hello/hello";
        }
    
    }

    The class accepts any request of the pattern /a/hello/* and any request using the GET method will call the hello() method.  Spring allows for controller methods to be very flexible.  hello() takes in the request object (to use to check if the user is logged in) and a model object to return data to the view.  The message created is added to the model map and the name of the view is returned (remember “hello/hello” maps to /WEB-INF/views/hello/hello).

  9. Finally, we are going to set up the “hello/hello” view.  First, we will set up an includes page that sets up the taglibs we will use.  Create the file war/WEB-INF/views/common/includes.jsp with the contents:
    <%@ page session="false"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

    Next,we’ll set up the actual view.  Create the file war/WEB-INF/views/hello/hello.jsp with the contents:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@page isELIgnored="false" %>
    <%@ include file="/WEB-INF/views/common/includes.jsp" %>
    
    <p>${message}</p>
    

    The first line of the jsp sets the contentType and the language of the page.  The next line is needed if you plan to use EL expressions (i.e. ${bean.name}).  Be sure you put isELIgnored, not isElIgnored like the will it play page for GAE has it listed, this took me several hours to figure out. The third line includes the taglibs from the last file we set up.  The final line displays the message attribute that was added to the model in the controller.

You should now be able to click “Debug” and run the application by visiting “localhost:8888/a/hello”.  Next up, I’m going to be adding a tutorial on integrating JDO for GAE’s Datastore into Spring.  If you have any questions or problems with the tutorial, feel free to comment.  I’ll try to get back to them as soon as I can.

References:

    • Sam
    • March 24th, 2010

    Firstly, I would like to thank you for the posting. It is very informative. However, I followed every instruction on the post but when I hit debug, this is what I got:

    Mar 24, 2010 12:21:38 PM org.springframework.web.servlet.FrameworkServlet initServletBean
    SEVERE: Context initialization failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘viewResolver’ defined in ServletContext resource [/WEB-INF/dispatcher-servlet.xml]: Instantiation of bean failed; nested exception is java.lang.IllegalStateException: No bean class specified on bean definition

    Do you know what else I would need to do? Any help is greatly appreciated. Thanks!

    • Mylo
    • April 5th, 2010

    Many thanks for providing this tutorial, it got me setup with Spring running on the GAE very quickly.

    One correction is the way you create the bean in dispatcher-servlet.xml

    Replace with this (as the code you give will not work):

  1. Hello in: war/WEB-INF/dispatcher-servlet.xml

    Should be:

    It works like a charm with GAE 1.3.3 and Spring 3.0.2 if anyone is interested :)

  2. As you mentioned, do you have a tutorial on integrating JDO for GAE’s Datastore into Spring? thanks.

    • Patrick
    • May 3rd, 2010

    Thanks for the nice tutorial. You forgot to define the beans class in dispatcher-servlet.xml

    Greets from Cologne
    Pat

  3. Hey Guys,

    I updated the dispatcher-servlet.xml example to include the correct code. Sorry for such a long delay!

    I should have a post up on using JDO, GAE and Spring in the next few days. I just completed a project with it a learned a lot! Thanks for the feedback.

  1. No trackbacks yet.