Spring MVC RESTful Web Service Example with Spring Data for MongoDB and ExtJS GUI

Spring MVC 4.0.6 RESTful Web Service Example with Spring Data for MongoDB 1.6.1 and ExtJS 2.2 GUI

This post will show another example of how to build a RESTful web service using Spring MVC 4.0.6, Spring Data for MongoDB 1.6.1 so that we can integrate the web application with a highly efficient datastore (MongoDB 2.6). In this tutorial we will walk you through building the web service and NoSQL database backend and show you how to implement a CRUD (Create, Read, Update and Delete) operations.

In addition, we will enhance our GUI by using ExtJS 2.2. I am using version 2.2 as it was one of the last remaining Open Source GPL licensed version of ExtJS. The last versions of ExtJS adds quite a bit of functionality so you might consider purchasing that product if you are planning on producing a commercial application.

For this post, we are building upon using our last post (Spring RESTful Web Service Example with JSON and Jackson using Spring Tool Suite) as a foundation.

In this post we will modify the our RestController such that it returns JSON that is formatted in a way that easily integrates with ExtJS JSON reader. In addition, we will remove all references to our internal HashMap-based datastore that was previously used. Lastly, we added an update rest end point which was missing in our rest API.

extjs grid populated

Getting Started using Spring Data

The primary goal of Spring Data is to make it easy to access both legacy relational databases in addition to new data technologies like NoSQL databases, map reduce frameworks and cloud based solutions. Spring Data for MongoDB is an umbrella project which aim to keep the consistent and familiar manner of the Spring based programming paradigm for new datastores.

In order to run this tutorial yourself, you will need the following:

Maven Project Object Model (pom.xml)

This Maven POM file (pom.xml) was automatically created for us by Spring Tool Suite when we select Spring MVC Project template. For this project we actually used the existing pom.xml file from the previous project and only needed to add the Spring Dara for MongoDB dependency as we wanted to fully integrate with MongoDB.

<!-- Spring Data for MongoDB-->
<dependency>
  <groupId>org.springframework.data</groupId>
  <artifactId>spring-data-mongodb</artifactId>
  <version>${org.spring-data-mongodb-version}</version>
</dependency>

Project Object Model – Full Listing (pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.avaldes</groupId>
  <artifactId>tutorial</artifactId>
  <name>SpringRestExample</name>
  <packaging>war</packaging>
  <version>1.0.0-BUILD-SNAPSHOT</version>
  <properties>
    <java-version>1.6</java-version>
    <org.springframework-version>4.0.6.RELEASE</org.springframework-version>
    <org.spring-data-mongodb-version>1.6.1.RELEASE</org.spring-data-mongodb-version>
    <org.aspectj-version>1.6.10</org.aspectj-version>
    <org.slf4j-version>1.6.6</org.slf4j-version>
  </properties>
  <dependencies>
    <!-- Spring -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${org.springframework-version}</version>
      <exclusions>
        <!-- Exclude Commons Logging in favor of SLF4j -->
        <exclusion>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
         </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>

    <!-- Spring Data for MongoDB-->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-mongodb</artifactId>
        <version>${org.spring-data-mongodb-version}</version>
    </dependency>

    <!-- AspectJ -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>${org.aspectj-version}</version>
    </dependency> 

    <!-- Jackson  -->
    <dependency>
      <groupId>org.codehaus.jackson</groupId>
      <artifactId>jackson-mapper-asl</artifactId>
      <version>1.9.13</version>
    </dependency>

    <!-- Logging -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>${org.slf4j-version}</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>${org.slf4j-version}</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${org.slf4j-version}</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.15</version>
      <exclusions>
        <exclusion>
          <groupId>javax.mail</groupId>
          <artifactId>mail</artifactId>
        </exclusion>
        <exclusion>
          <groupId>javax.jms</groupId>
          <artifactId>jms</artifactId>
        </exclusion>
        <exclusion>
          <groupId>com.sun.jdmk</groupId>
          <artifactId>jmxtools</artifactId>
        </exclusion>
        <exclusion>
          <groupId>com.sun.jmx</groupId>
          <artifactId>jmxri</artifactId>
        </exclusion>
      </exclusions>
      <scope>runtime</scope>
    </dependency>

    <!-- @Inject -->
    <dependency>
      <groupId>javax.inject</groupId>
      <artifactId>javax.inject</artifactId>
      <version>1</version>
    </dependency>

    <!-- Servlet -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <!-- Test -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.7</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Configure Spring Web DispatcherServlet (dispatcher-servlet.xml)

Modify the dispatcher-servlet.xml and add the necessary MongoDB configurations. You will notice that I have added MongoTemplate which is used for the mongo operations and MongoFactoryBean which creates the mongo instance to our dispatcher-servlet.xml. MongoTemplate is configured to use the database settings via MongoFactoryBean.

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

  <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

  <!-- Enables the Spring MVC @Controller programming model -->
  <annotation-driven />

  <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
  <resources mapping="/resources/**" location="/resources/" />

  <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
  <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
  </beans:bean>

  <!-- Define the MongoTemplate which handles connectivity with MongoDB -->
  <beans:bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <beans:constructor-arg name="mongo" ref="mongo" />
    <beans:constructor-arg name="databaseName" value="gcdr" />
  </beans:bean>

  <!-- Factory bean that creates the MongoDB instance -->
  <beans:bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
    <beans:property name="host" value="localhost"/>
  </beans:bean>

  <!-- Use this post processor to translate any MongoExceptions thrown in @Repository annotated classes -->
  <beans:bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

  <context:component-scan base-package="com.avaldes" />

</beans:beans>

IssuerRepository Data Access Object (DAO) (IssuerRepository.java)

In this class you will notice two annotations being used. The first one, @Repository indicates that the class IssuerRepository fulfills the role of a Data Access Object of a repository. This class will handle all of the persistence and database access for us.

The second annotation, @Autowired indicates that MongoTemplate is autowired from the Spring configuration, in this case our dispatcher-servlet.xml file.

package com.avaldes.dao;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import com.avaldes.model.Issuer;

@Repository
public class IssuerRepository {
  public static final String COLLECTION_NAME = "issuer";

  @Autowired
  private MongoTemplate mongoTemplate;

  public void addIssuer(Issuer issuer) {
    if (!mongoTemplate.collectionExists(Issuer.class)) {
      mongoTemplate.createCollection(Issuer.class);
    }
    mongoTemplate.insert(issuer, COLLECTION_NAME);
  }

  public Issuer getIssuerByTicker(String ticker) {
    return mongoTemplate.findOne(
      Query.query(Criteria.where("ticker").is(ticker)), Issuer.class, COLLECTION_NAME);
  }

  public List<Issuer> getAllIssuers() {
    return mongoTemplate.findAll(Issuer.class, COLLECTION_NAME);
  }

  public Issuer deleteIssuer(String ticker) {
    Issuer issuer = mongoTemplate.findOne(
      Query.query(Criteria.where("ticker").is(ticker)), Issuer.class, COLLECTION_NAME);
    mongoTemplate.remove(issuer, COLLECTION_NAME);

    return issuer;
  }

  public Issuer updateIssuer(String ticker, Issuer issuer) {
    Query query = new Query();
    query.addCriteria(Criteria.where("ticker").is(ticker));

    Update update = new Update();
    update.set("issuerName", issuer.getIssuerName());
    update.set("issuerType", issuer.getIssuerType());
    update.set("country", issuer.getCountry());

    mongoTemplate.updateFirst(query, update, Issuer.class);

    return issuer;
  }
}

RESTful Web Service End Points

#URIMethodDescription
1/tutorial/rest/issuersGETReturns a list of all the issuers available in MongoDB
2/tutorial/rest/issuer/{ticker}GETReturn the issuer based on the Ticker in MongoDB
3/tutorial/rest/issuer/delete/{ticker}DELETEDelete the issuer in the MongoDB datastore based on the Ticker
4/tutorial/rest/issuer/update/{ticker}PUTUpdates the issuer in the MongoDB datastore based on the Ticker
5/tutorial/rest/issuer/createPOSTInserts the issuer into the MongoDB datastore based on the contents of the form

Controller Class (RestController.java)

Our RestController class is the main class that contains all web service mapping end points defined in our table above. The @Controller annotation indicates that this particular class is playing the role of a controller.

package com.avaldes.tutorial;

import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.avaldes.dao.IssuerRepository;
import com.avaldes.model.Issuer;
import com.avaldes.rest.multipleIssuerResponse;
import com.avaldes.rest.restResponse;
import com.avaldes.rest.singleIssuerResponse;

/**
 * Handles requests for the application home page.
 */
@Controller
public class RestController {

  private static final Logger logger = LoggerFactory.getLogger(RestController.class);

  @Autowired
    private IssuerRepository issuerRepository;

  /**
   * Simply selects the home view to render by returning its name.

   */
  @RequestMapping(value = "/", method = RequestMethod.GET)
  public String home(Locale locale, Model model) {
    logger.info("Default Home REST page. The client locale is {}.", locale);

    Date date = new Date();
    DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
    String formattedDate = dateFormat.format(date);
    model.addAttribute("serverTime", formattedDate );
 
    return "status";
  }
 
  @RequestMapping(value="/issuers", method=RequestMethod.GET)
  @ResponseBody
  public multipleIssuerResponse getAllIssuers() {
    logger.info("Inside getAllIssuers() method...");

    List<Issuer> allIssuers = issuerRepository.getAllIssuers();
    multipleIssuerResponse extResp = new multipleIssuerResponse(true, allIssuers);
 
    return extResp;
  }
 
  @RequestMapping(value="/issuer/{ticker}", method=RequestMethod.GET)
  @ResponseBody
  public singleIssuerResponse getIssuerByTicker(@PathVariable("ticker") String ticker) {
    Issuer myIssuer = issuerRepository.getIssuerByTicker(ticker);
 
    if (myIssuer != null) {
      logger.info("Inside getIssuerByTicker, returned: " + myIssuer.toString());
    } else {
      logger.info("Inside getIssuerByTicker, ticker: " + ticker + ", NOT FOUND!");
    }
 
    singleIssuerResponse extResp = new singleIssuerResponse(true, myIssuer);
    return extResp; 
  }

  @RequestMapping(value="/issuer/delete/{ticker}", method=RequestMethod.DELETE)
  @ResponseBody
  public restResponse deleteIssuerByTicker(@PathVariable("ticker") String ticker) {
    restResponse extResp;

    Issuer myIssuer = issuerRepository.deleteIssuer(ticker);

    if (myIssuer != null) {
      logger.info("Inside deleteIssuerByTicker, deleted: " + myIssuer.toString());
      extResp = new restResponse(true, "Successfully deleted Issuer: " + myIssuer.toString());
    } else {
      logger.info("Inside deleteIssuerByTicker, ticker: " + ticker + ", NOT FOUND!");
      extResp = new restResponse(false, "Failed to delete ticker: " + ticker);
    }

    return extResp;
  }

  @RequestMapping(value="/issuer/update/{ticker}", method=RequestMethod.PUT)
  @ResponseBody
  public restResponse updateIssuerByTicker(@PathVariable("ticker") String ticker, @ModelAttribute("issuer") Issuer issuer) {
    restResponse extResp;

    Issuer myIssuer = issuerRepository.updateIssuer(ticker, issuer);

    if (myIssuer != null) {
      logger.info("Inside updateIssuerByTicker, updated: " + myIssuer.toString());
      extResp = new restResponse(true, "Successfully updated Issuer: " + myIssuer.toString());
    } else {
      logger.info("Inside updateIssuerByTicker, ticker: " + ticker + ", NOT FOUND!");
      extResp = new restResponse(false, "Failed to update ticker: " + ticker);
    }

    return extResp;
  }

  @RequestMapping(value="/issuer/addIssuer", method=RequestMethod.POST)
  @ResponseBody
  public restResponse addIssuer(@ModelAttribute("issuer") Issuer issuer) {
    restResponse extResp;

    if (issuer.getTicker() != null && issuer.getTicker().length() > 0) {
      logger.info("Inside addIssuer, adding: " + issuer.toString());
      issuerRepository.addIssuer(issuer);
      extResp = new restResponse(true, "Successfully added Issuer: " + issuer.getTicker());
    } else {
      logger.info("Failed to insert...");
      extResp = new restResponse(false, "Failed to insert...");
    }

    return extResp;
  } 
}

restResponse JSON Message Format (restResponse.java)

The purpose of this class is to return properly formatted JSON back to out ExtJS UI. The captions below you give you a good idea of how the messages are constructed. The ExtJS application would then process the Ajax message to determine whether the call was successful or not, and display the appropriate message in the event of a failure as a popup alert to the user.

restResponse SUCCESS Message

issuer delete by ticker cs

restResponse FAILURE Message

issuer delete by ticker failure
package com.avaldes.rest;

public class restResponse {
  private boolean success;
  private String message;

  public restResponse(boolean success, String message) {
    this.success = success;
    this.message = message;
  }

  public boolean isSuccess() {
    return success;
  }
  public void setSuccess(boolean success) {
    this.success = success;
  }
  public String getMessage() {
    return message;
  }
  public void setMessage(String message) {
    this.message = message;
  }
}

singleIssuerResponse JSON Message Format (singleIssuerResponse.java)

The purpose of this class is to return properly formatted containing a single issuer in JSON back to out ExtJS UI. The caption below you give you a good idea of how the message is constructed.

issuer ext get by ticker ibm
package com.avaldes.rest;

import com.avaldes.model.Issuer;

public class singleIssuerResponse {
  private boolean success;
  private Issuer issuer;

  public singleIssuerResponse(boolean success, Issuer issuer) {
    this.success = success;
    this.issuer = issuer;
  }

  public boolean isSuccess() {
    return success;
  }
  public void setSuccess(boolean success) {
    this.success = success;
  }
  public Issuer getIssuers() {
    return issuer;
  }
  public void setIssuer(Issuer issuer) {
    this.issuer = issuer;
  }
}

multipleIssuerResponse JSON Message Format (multipleIssuerResponse.java)

The purpose of this class is to return properly formatted containing multiple issuers in JSON back to out ExtJS UI. The caption below you give you a good idea of how the message is constructed.

issuer ext get all
package com.avaldes.rest;

import java.util.List;

import com.avaldes.model.Issuer;

public class multipleIssuerResponse {
  private boolean success;
  private List<Issuer> issuers;

  public multipleIssuerResponse(boolean success, List<Issuer> issuers) {
    this.success = success;
    this.issuers = issuers;
  }

  public boolean isSuccess() {
    return success;
  }
  public void setSuccess(boolean success) {
    this.success = success;
  }
  public List<Issuer> getIssuers() {
    return issuers;
  }
  public void setIssuers(List<Issuer> issuers) {
    this.issuers = issuers;
  }
}

Model Class (Issuer.java)

The simple model is used as a basis for storing the fields into MongoDB as a document in the collection. This class contains two annotations. The first one, the @Document annotation identifies objects or entities that are going to be persisted to MongoDB. The next one, @Id is used to identify the field that will be used as an ID in Mongo. This ID is labeled _id in MongoDB.

package com.avaldes.model;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document
public class Issuer {
  @Id
  private String id;
  private String ticker;

  private String issuerName;
  private String issuerType;
  private String country;

  public Issuer() {
  }

  public Issuer(String ticker, String issuerName, String issuerType, String country) {
    setTicker(ticker);
    setIssuerName(issuerName);
    setIssuerType(issuerType);
    setCountry(country);
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getTicker() {
    return ticker;
  }

  public void setTicker(String ticker) {
    this.ticker = ticker;
  }

  public String getIssuerName() {
    return issuerName;
  }

  public void setIssuerName(String issuerName) {
    this.issuerName = issuerName;
  }

  public String getIssuerType() {
    return issuerType;
  }

  public void setIssuerType(String issuerType) {
    this.issuerType = issuerType;
  }

  public String getCountry() {
    return country;
  }

  public void setCountry(String country) {
    this.country = country;
  }

  public String toString() {
    return "[" + getTicker()
        + ", " + getIssuerName()
        + ", " + getIssuerType()
        + ", " + getCountry()
        + "]";
  }
}

ExtJS 2.2 GUI

Below you will find the complete source for EXTJS user interface. I will be creating a follow up post on the ExtJS code as it would be beyond the scope of this post to cover it in any detail. I will update this post once that has been done.

I have added the post, Building ExtJS Grid Panel User Interface with Spring MVC Rest and MongoDB Backend to discuss the source code used in building the ExtJS application is detail.

GUI Web Page (index.jsp)

<!DOCTYPE html>
<html>
<head>
<title>Database Driven Grid</title>
  <link rel="stylesheet" href="include/extjs/resources/css/ext-all.css" />
  <link rel="stylesheet" href="include/styles.css">
  <script src="include/extjs/adapter/ext/ext-base.js"></script>
  <script src="include/extjs/ext-all-debug.js"></script>
  <script>
    Ext.onReady(function() {
      //add data store here
      var store = new Ext.data.Store({
        url: '/tutorial/rest/issuers',
        reader: new Ext.data.JsonReader({
          root: 'issuers',
          id: 'ticker'
        }, [
          'ticker',
          'issuerName',
          'issuerType',
          'country' 
        ])
      });
      store.load();
      
      

      var ds_model = Ext.data.Record.create([
        'ticker',
        'issuerName',
        'issuerType',
        'country'
      ]);
      

      var ticker_edit = new Ext.form.TextField();
      var name_edit = new Ext.form.TextField();
      var type_edit = new Ext.form.TextField();
      var country_edit = new Ext.form.TextField();
      

      var sm2 = new Ext.grid.CheckboxSelectionModel();
      var grid = new Ext.grid.EditorGridPanel({
        id:'button-grid',
        store: store,
        cm: new Ext.grid.ColumnModel([
        new Ext.grid.RowNumberer(),
          {header: "Ticker", dataIndex: 'ticker', sortable: true},
          {id: 'name', header: "Issuer Name", dataIndex: 'issuerName', sortable: true, editor: name_edit},
          {header: "Issuer Type", dataIndex: 'issuerType', sortable: true, width: 75, editor: type_edit},
          {header: "Country", dataIndex: 'country', sortable: true, width: 75, editor: country_edit}
        ]),
            


        selModel: new Ext.grid.RowSelectionModel({
          singleSelect: false
        }),
            


        listeners: {
          afteredit: function(e) {
            var _ticker = e.record.data.ticker;
            var _issuerName = (e.field == 'issuerName') ? e.value : e.record.data.issuerName;
            var _issuerType = (e.field == 'issuerType') ? e.value : e.record.data.issuerType;
            var _country = (e.field == 'country') ? e.value : e.record.data.country;
                

            var restURL = '/tutorial/rest/issuer/update/' + _ticker;
            var conn = new Ext.data.Connection();
              conn.request({
                url: restURL,
                method: 'PUT',
                params: {
                  ticker: _ticker,
                  issuerName: _issuerName,
                  issuerType: _issuerType,
                  country: _country
                },

                success: function(a, response) {
                  e.record.commit();
                },
								
                failure: function(a, response) {
                  Ext.Msg.alert("Failed", response.result.message);
                  e.record.reject();
                }
            });
          }
        },

				viewConfig: {
          forceFit:true
        },

        // inline toolbars
        tbar:[{
            text:'Add Issuer',
                tooltip:'Add a new Issuer',
                icon: 'images/addIssuer16.png',
                cls: 'x-btn-text-icon',
                handler: function() {
                  var form = new Ext.form.FormPanel({
                    baseCls: 'x-plain',
                    labelWidth: 75,
                    name: 'MyForm',
                    url: '/tutorial/rest/issuer/addIssuer',
                    defaultType: 'textfield',

                    items: [{
                        fieldLabel: 'Ticker',
                        id: 'ticker', 

                        name: 'ticker',
                        xtype: 'textfield',
                        maxLength: 10,
                        allowBlank:false,
                        width: 100,
												listeners: {
                          afterrender: function(field) {
                          field.focus(false, 200);
                        }
                      }
                    },{
                        fieldLabel: 'Issuer Name',
                        id: 'issuerName',
                        name: 'issuerName',
                        allowBlank:false,
                        anchor: '100%'  // anchor width by percentage
                    }, {
                      fieldLabel: 'Issuer Type',
                      id: 'issuerType',
                        name: 'issuerType',
                        maxLength: 10,
                        width: 90

                    }, {
                      fieldLabel: 'Country',
                      id: 'country',
                        name: 'country',
                        maxLength: 20,
                        width: 150

                    }]
                });
              

              var window = new Ext.Window({
                    title: 'Add New Issuer',
                    width: 350,
                    height:180,
                    minWidth: 350,
                    minHeight: 180,
                    layout: 'fit',
                    plain:true,
                    bodyStyle:'padding:5px;',
                    buttonAlign:'center',
                    resizable: false,
                    items: form,

                    buttons: [{
                        text: 'Save Issuer',
                        handler: function () {
                          var formTicker = Ext.get('ticker').getValue();
                          var formName = Ext.get('issuerName').getValue();
                          var formType = Ext.get('issuerType').getValue();
                          var formCountry = Ext.get('country').getValue();
                          

                          if (form.getForm().isValid()) {
                            form.getForm().submit({
                            method: 'POST',
                            url: '/tutorial/rest/issuer/addIssuer',

                            success: function(a, response) {
                              grid.getStore().insert(
                              0,
                              new ds_model({
                                ticker: formTicker,
                                issuerName: formName,
                                issuerType: formType,
                                country: formCountry
                              })
                             );
                             window.close();
                            },

                          failure: function(a, response) {
                            Ext.Msg.alert("Failed", response.result.message);
                          }
                        });
                      }
                    }
                  },{
                    text: 'Cancel',
                    handler: function () {
                      if (window) {
                        window.close();
                      }
                    }
                  }]
                });
                window.show();
              }
            },'-',{
                text:'Remove Issuer',
                tooltip:'Remove the selected issuer',
                icon: 'images/removeIssuer16.png',
                cls: 'x-btn-text-icon',
                handler: function() {
                  var sm = grid.getSelectionModel();
                  var sel = sm.getSelected();
                  if (sm.hasSelection()) {
                    Ext.Msg.show({
                      title: 'Remove Issuer',
                      buttons: Ext.MessageBox.YESNOCANCEL,
                      msg: 'Remove ' + sel.data.issuerName + '?',
                      fn: function(btn) {
                        if (btn == 'yes') {
                          var conn = new Ext.data.Connection();
                          var restURL = '/tutorial/rest/issuer/delete/' + sel.data.ticker;
                          conn.request({
                            method: 'DELETE',
                            url: restURL,
 
														success: function(resp,opt) {
                              grid.getStore().remove(sel);
                            },
                            
														failure: function(resp,opt) {
                              Ext.Msg.alert('Error', 'Unable to delete issuer');
                            }
                          });
                        }
                      }
                    });
                  };
                }
            }],

            width: 600,
            height: 350,
            collapsible: true,
            frame: true,
            clicksToEdit: 2,
            animCollapse: false,
            title:'Issuer Grid Panel for MongoDB Access',
            iconCls:'icon-grid',
            renderTo: document.body
        });
    });
  </script>
</head>
<body>
  <h1>Spring RESTful Web Service using mongoDB and extJS Example</h1>
  <br>
  <p>This example uses a REST Web Service that will query the database and generate appropriate JSON for the Grid to load.</p>
  <br>
  <div id="mygrid"></div>
</body>
</html>

Let’s Test it Out

Once that ExtJS application has started, it will make a call to get all the issuers via the /tutorial/rest/issuers end point. As you can see from the screenshot below, the web service makes a call to MongoDB and extracts all of the issuers available from the MongoDB collection and returns them back as a properly formatted JSON string.

Displaying All Issuers from MongoDB

extjs grid populated

Adding a New Issuer into MongoDB

extjs grid add issuer

Deleting an Issuer from MongoDB

extjs grid del issuer

Updating an Issuer in MongoDB

extjs grid update issuer

Web Application Console Output

spring mvc console

Download the Code

That’s It!

I hope you enjoyed this tutorial. It was certainly a lot of fun putting it together and testing it out. Please continue to share the love and like us so that we can continue bringing you quality tutorials. Happy Coding!!!

spring mvc ext mongo

Related Spring Posts

  • Creating Hello World Application using Spring MVC on Eclipse IDE
    In this tutorial we will go into some detail on how to set up your Eclipse IDE environment so that you can develop Spring MVC projects. In this post, we will create our first Spring MVC project with the all to familiar “Hello World” sample program.
  • Spring MVC Form Handling Example
    The following tutorial will guide you on writing a simple web based application which makes use of forms using Spring Web MVC framework. With this web application you will be able to interact with the customer entry form and enter all of the required values and submit them to the backend processes. I have taken the liberty of using CSS to beautify and transform the HTML page from a standard drab look and feel to a more appealing view.
  • Spring @RequestHeader Annotation Example
    In this tutorial, we will discuss the different ways that Spring MVC allow us to access HTTP headers using annotation. We will discuss how to access individual header fields from the request object as well accessing all the headers by supplying Map and then iterating through the LinkedHashMap collection. We will also show you how to set the headers in the response object.
  • Spring MVC Exception Handling using @ExceptionHandler with AngularJS GUI
    Good exception handling is a essential part of any well developed Application Framework and Spring MVC is no exception — pardon the pun. Spring MVC provides several different ways to handle exceptions in our applications. In this tutorial, we will cover Controller Based Exception Handling using the @ExceptionHandler annotation above the method that will handle it.
  • Spring RESTful Web Service Example with JSON and Jackson using Spring Tool Suite
    For this example, I will be using Spring Tool Suite (STS) as it is the best integrated development environment for building the Spring framework projects. Spring is today's leading framework for building Java, Enterprise Edition (Java EE) applications. One additional feature that makes Spring MVC so appealing is that it now also supports REST (REpresentational State Transfer) for build Web Services.
  • Spring MVC RESTful Web Service Example with Spring Data for MongoDB and ExtJS GUI
    This post will show another example of how to build a RESTful web service using Spring MVC 4.0.6, Spring Data for MongoDB 1.6.1 so that we can integrate the web application with a highly efficient datastore (MongoDB 2.6). In this tutorial we will walk you through building the web service and NoSQL database backend and show you how to implement CRUD (Create, Read, Update and Delete) operations.
  • Building DHTMLX Grid Panel User Interface with Spring MVC Rest and MongoDB Backend
    In this tutorial we will show how easy it is to use DHTMLX dhtmlxGrid component while loading JSON data with Ajax pulling in data from the Spring MVC REST web service from our MongoDB data source. You will see how simple it is to create a visually appealing experience for your client(s) with minimal javascript coding.
  • Spring MVC with JNDI Datasource for DB2 on AS/400 using Tomcat
    In this tutorial we will discuss how to set up Spring MVC web services and configure a JNDI Datasource using Tomcat and connect to IBM DB2 Database on a AS/400. JNDI (Java Naming and Directory Interface) provides and interface to multiple naming and directory services.
  • Java Spring MVC Email Example using Apache Velocity
    In this tutorial we will discuss how to set up a Java Spring MVC RESTful Webservice with Email using Apache Velocity to create a Velocity template that is used to create an HTML email message and embed an image, as shown below, using MIME Multipart Message.
  • Implementing Basic and Advanced Search using Angular Material Design, Grid-UI, Spring MVC REST API and MongoDB Example
    In this tutorial we will discuss how to implement basic and advanced search techniques in MongoDB using AngularJS and Google’s Material Design with Spring MVC REST API backend. The advanced search user interface (UI) will use logical operators and build a JSON object which contains the search field name, boolean or logical operator and the search value.
  • Spring MVC Interceptor using HandlerInterceptorAdapter Example
    In this tutorial we will discuss how to use the HandlerInterceptorAdapter abstract class to create a Spring MVC interceptor. These interceptors are used to apply some type of processing to the requests either before, after or after the complete request has finished executing.

Please Share Us on Social Media

Facebooktwitterredditpinterestlinkedinmail

Leave a Reply

Your email address will not be published. Required fields are marked *