Nilabh has posted 1 posts at DZone. View Full User Profile

Spring REST Services with GWT

10.06.2012
| 7578 views |
  • submit to reddit

For my own interest I started exploring Spring REST Services with GWT. It took some time to figure it out and then I came accross RestyGWT. With the help of RestyGWT, I managed to integrate GWT with Spring REST Services. My idea was to keep the GWT way of creating the service and serviceAsync and yet make a REST call. Below are the steps which will help achieve above.

My preffered development environment is Eclipse, so as a prerequisite you must have Eclipse with Maven support installed.

Lets Begin,

  1. Create a Maven project, goto File-->New-->Other. In the wizard type "Maven". Select Maven Project and click on Next.
  2. In the "Select project name and location" page of the wizard, make sure that "Create a simple project (skip archetype selection)" option is checked, hit "Next" to continue with default values.
  3. In the "Enter group id for the artifact" page of the wizard, enter values for group id and artifactid. Select the packaging as "war", hit "Finish" to exit the wizard and to create your project.
 Modify the POM file to add required dependencies as below
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.sagar.restgwt</groupId>
	<artifactId>RestGWT</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<dependencies>
		<dependency>
			<groupId>com.google.gwt</groupId>
			<artifactId>gwt-servlet</artifactId>
			<version>${gwt.version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>com.google.gwt</groupId>
			<artifactId>gwt-user</artifactId>
			<version>${gwt.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.fusesource.restygwt</groupId>
			<artifactId>restygwt</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>javax.ws.rs</groupId>
			<artifactId>jsr311-api</artifactId>
			<version>1.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-mapper-asl</artifactId>
			<version>1.4.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
	</dependencies>
	<properties>
		<basedir>.</basedir>
		<gwt.version>2.5.0-rc1</gwt.version>
		<java-version>1.6</java-version>
		<org.springframework.version>3.1.1.RELEASE</org.springframework.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<webappDirectory>${project.build.directory}\${project.build.finalName}</webappDirectory>
	</properties>
	<build>
		<finalName>restgwt</finalName>
		<outputDirectory>${webappDirectory}/WEB-INF/classes</outputDirectory>
		<plugins>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>gwt-maven-plugin</artifactId>
				<version>2.5.0-rc1</version>
				<executions>
					<execution>
						<goals>
							<goal>compile</goal>
							<goal>test</goal>
							<goal>generateAsync</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<hostedWebapp>${webappDirectory}</hostedWebapp>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>${java-version}</source>
					<target>${java-version}</target>
					<showWarnings>true</showWarnings>
				</configuration>
			</plugin>
		</plugins>
	</build></project> 

"Update Project Configuration" by Right clicking on your project-->Maven.

The below steps assumes that your are aware of the GWT project structure. Create your GWT module. This can be done by installing GWT plugin for Eclipse. Once the GWT module is ready update your <Module>.gwt.xml with the below given content.

<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='restgwt'>
	<!-- Inherit the core Web Toolkit stuff. -->
	<inherits name='com.google.gwt.user.User' />
	<inherits name='org.fusesource.restygwt.RestyGWT' />
	<inherits name='com.google.gwt.user.theme.standard.Standard' />

	<!-- Specify the app entry point class. -->
	<entry-point class='com.sagar.restgwt.client.RestGWT' />

	<!-- Specify the paths for translatable code -->
	<source path='client' />
	<source path='shared' />
</module>

In the client package create the service to make REST Call. With this approach we dont have to create the ServiceAsync interface. We will be creating our service interface by extending the "RestService", provided by RestyGWT

Code Snippet: 

InfoService.Java [ A service interface to make REST call. ]
@Path("/service")
public interface InfoService extends RestService {
	public static class Util {
		private static InfoService instance;
		public static InfoService getService() {
			if (instance == null) {
				instance = GWT.create(InfoService.class);
			}
			Resource resource = new Resource(GWT.getModuleBaseURL() + "service");
	        ((RestServiceProxy) instance).setResource(resource);
	        
			return instance;
		}
	}
	
	@GET
	@Path("/loadInfo")
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public void getInfo(MethodCallback<OrderConfirmation> callback);
}

 
OrderConfirmation.java [ Model which will be returned as a response. ]
public class OrderConfirmation {
    public String message;
    public Long ready_time;

    /**
     * Example of how to create an instance of a JsonEncoderDecoder for a data
     * transfer object.
     */
    public interface OrderConfirmationJED extends JsonEncoderDecoder<OrderConfirmation> {
    }

    @Override
    public String toString() {
        if (GWT.isClient()) {
            OrderConfirmationJED jed = GWT.create(OrderConfirmationJED.class);
            return jed.encode(this).toString();
        }
        
        return super.toString();
    }
}
 
RestGWT.java [ GWT module entrypoint to see things running. ]
public class RestGWT implements EntryPoint {
	public void onModuleLoad() {
		Button button = new Button("Click Me");
		button.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				InfoService.Util.getService().getInfo(new MethodCallback<OrderConfirmation>() {
					@Override
					public void onSuccess(Method method, OrderConfirmation response) {
						RootPanel.get().add(new Label(response.toString()));
					}
					
					@Override
					public void onFailure(Method method, Throwable exception) {
						GWT.log("Error");
					}
				});
			}
		});
		
		RootPanel.get().add(button);
	}
}
 

Create the Spring managed controller as below, this should be presnt in the "server" package as per GWT project structure. Also you can notice that we don't have to implement our service interface.

RestGWTController.java [ Spring managed controller. ]
@Controller
public class RestGWTController {
	@RequestMapping(value = "/loadInfo", method = RequestMethod.GET, headers = "Accept=application/json")
	public @ResponseBody OrderConfirmation handleRequest(HttpServletRequest request,
			  HttpServletResponse response) throws ServletException, IOException {
		GreetingServiceEndpoint endpoint = greetingService.getGreetingServiceEndpointPort();
		
		OrderConfirmation confirmation = new OrderConfirmation();
		confirmation.message = endpoint.sayHello();
        confirmation.ready_time = System.currentTimeMillis() + 1000 * 60 * 30;
        
		return confirmation;
	}
}
 

Settings required for Spring

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<!-- Name the application -->
	<display-name>Rest GWT</display-name>
	<description>This is web-project for RestGWT</description>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/applicationContext.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<servlet>
		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/classes/action-servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
		<url-pattern>/restgwt/service/*</url-pattern>
	</servlet-mapping>
	<welcome-file-list>
		<welcome-file>RestGWT.html</welcome-file>
	</welcome-file-list>
</web-app>
 

src/main/webapp/WEB-INF/applicationCotext.xml 

<?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">

	<!-- registers all of Spring's standard post-processors for annotation-based configuration -->
	<context:annotation-config />
</beans>
 

src/main/webapp/WEB-INF/classes/action-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
		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">

	<!-- Scans the classpath of this application for @Components to deploy as 
		beans -->
	<context:component-scan base-package="com.sagar.restgwt.server" />

	<!-- Configures the @Controller programming model -->
	<mvc:annotation-driven />

	<bean
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
		<property name="messageConverters">
			<list>
				<bean
					class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
			</list>
		</property>
	</bean>
</beans> 

Now all configuration is completed.

To build the application right click on your project → Run As → Maven Install. This will create the war file in your project's target/restgwt folder. To test this approach we are going to deploy our web application to an Apache Tomcat 7 server.

To launch the application point your browser to the following address

http://localhost:8080/restgwt/

 

Enjoy Coding

Nilabh

0
Published at DZone with permission of its author, Nilabh Sagar.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)