DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
View Events Video Library
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Integrating PostgreSQL Databases with ANF: Join this workshop to learn how to create a PostgreSQL server using Instaclustr’s managed service

Mobile Database Essentials: Assess data needs, storage requirements, and more when leveraging databases for cloud and edge applications.

Monitoring and Observability for LLMs: Datadog and Google Cloud discuss how to achieve optimal AI model performance.

Automated Testing: The latest on architecture, TDD, and the benefits of AI and low-code tools.

Related

  • My Experiences with Maven in IntelliJ IDEA and NetBeans IDE
  • Open Source Integration With Apache Camel and How Fuse IDE Can Help
  • Hack OpenJDK with NetBeans IDE
  • Extending Swagger and Spring Doc Open API

Trending

  • How To Optimize Feature Sets With Genetic Algorithms
  • Decoding Business Source Licensing: A New Software Licensing Model
  • The Emergence of Cloud-Native Integration Patterns in Modern Enterprises
  • Exploring Sorting Algorithms: A Comprehensive Guide
  1. DZone
  2. Coding
  3. Frameworks
  4. ExtJS 4.2, Spring MVC 3.2.4, and Maven Example Using NetBeans IDE 7.3

ExtJS 4.2, Spring MVC 3.2.4, and Maven Example Using NetBeans IDE 7.3

Luis Vargas user avatar by
Luis Vargas
·
Dec. 03, 13 · Tutorial
Like (0)
Save
Tweet
Share
49.70K Views

Join the DZone community and get the full member experience.

Join For Free

This tutorial will walk you through how to implement a CRUD (Create, Read, Update, Delete) DataGrid using ExtJS 4.2, Spring MVC 3.2.4 and Maven with NetBeans IDE 7.3.

What do we usually want to do with data?

  • Create (Insert)
  • Read / Retrieve (Select)
  • Update (Update)
  • Delete / Destroy (Delete)

In this example, I’m going to use JSON as a data format exchange between the browser and the server.

1. Create a new Project in NetBeans IDE

  1. Go to File > New Project or press ctrl+shift+N
  2. Select maven > Project from Archetype and click next
  3. In the search-box write extjs and select extjs-springmvc-webapp and click next
  4. Enter Project Name, Location, and Package and click finish
Finally you are going to get a project directory like this one:


2. Modify the project

At this moment you can run your project and it is going to show you a grid in which you can edit 2 users. However this archetype has a little problem. If you see the file UserService.java that is inside com.extjs.spring.services package, it uses a method called parseUserJson which is used by updateUser method. 

...
    /**
     * Update a user in the system
     */
    @RequestMapping(value = "/user/update", method = RequestMethod.POST)
    public Map updateUser( HttpServletRequest request, HttpServletResponse response, Principal principal
            , @RequestBody String json ) throws Exception
    {
        //TODO replace this with your real code here.
        Collection<User> parsedUsers = parseUserJson(json);

        // Update all of the users (client is sending us array of users in json)
        if ( parsedUsers != null )
        {
            for (User parsedUser : parsedUsers)
            {
                User localUser = users.get(parsedUser.getId());
                if ( localUser == null )
                {
                    throw new RuntimeException("Invalid User");
                }

                // save changes to local user
                localUser.setName(parsedUser.getName());
                localUser.setEmail(parsedUser.getEmail());
            }
        }


        Map results = new HashMap();
        results.put("succes", true);
        return results;
    }


    /**
     * Parse an json packet of user(s)
     */
    private Collection<User> parseUserJson( String json ) throws Exception
    {
        try
        {
            if ( json.startsWith("[") && json.endsWith("]") )
            {
                // array of users
                ObjectMapper mapper = new ObjectMapper();
                TypeReference ref = new TypeReference<Collection<User>>(){};
                Collection<User> user = (Collection<User>) mapper.readValue(json, ref);
                return user;
            }
            else
            {
                // Single object
                ObjectMapper mapper = new ObjectMapper();
                Collection<User> users = new ArrayList<User>();
                users.add( (User) mapper.readValue(json, User.class) );
                return users;
            }
        }
        catch (Exception ex)
        {
            throw new RuntimeException("Invalid USER Json");
        }
    }
...

The problem with that approach is that if we want to create more Models Objects or POJOs, we need to create a parser method for every controller. 

An option to solve this problem would be to create a base-controller and extend all new controllers from it. However, we still need to call the parser method every time that we read an object sent as @RequestBody parameter. Another option could be create a util or helper class that implements this method, and call it from controllers, but we still need to call that method every time that we need to deserialize a @RequestBody.

By default, in spring controllers, if we pass a class or a List<Class> to the @RequestBody parameter, it parses the string and converts the object directly. For example: 

    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public void updateUser(@RequestBody List<User> inUsers) throws Exception    {
        for (User user : inUsers) {
            User localUser = users.get(user.getId());
            if (localUser == null) {
                throw new RuntimeException("Invalid User");
            }

            // save changes to local user
            localUser.setName(user.getName());
            localUser.setEmail(user.getEmail());
        }
    }

This could be the best solution, but we have another problem. When we only edit one row in our grid it sends the next json to the server.

{"id":"1","name":"Eds","email":"ed@sencha.com"}

As you can see, it sends the object without the square brackets "[..]" that represents an array. ie:

[{"id":"1","name":"Eds","email":"ed@sencha.com"}]

That means that it is only going to work when we edit two or more rows in the grid since it sends an array of objects, ie:

[{"id":"1","name":"Edss","email":"ed@sencha.com"},{"id":"2","name":"Tommys","email":"tommy@sencha.com"}]

There are two possible solutions:

  • Modify ExtJS Store to send always an array instead a single object. Since I don't know how to do that, and it could break other parts of the framework, I discarded this option
  • Create a CustomMappingJacksonHttpMessageConverter for Spring. To me this is a better option since doesn't affects anything in Spring Framework internally.
To do the second option we need to do 3 things:
  1. Create the CustomMappingJacksonHttpMessageConverter java Class.
  2. Instantiate that class inside the Spring Servlet configuration file ( in this case I am going to use XML)
  3. Add some Apache commons libraries to our pom.xml since are going to be required by our custom converter class.
1. Create the CustomMappingJacksonHttpMessageConverter java Class
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.springframework.http.converter.json;

import com.fasterxml.jackson.databind.JavaType;
import java.io.IOException;
import java.lang.reflect.Type;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageNotReadableException;

/**
 *
 * @author luis
 */
public class CustomMappingJacksonHttpMessageConverter extends MappingJackson2HttpMessageConverter {

    @Override
    public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {

        JavaType javaType = getJavaType(type, contextClass);
        return readJavaType(javaType, inputMessage);
    }

    private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) {
        try {
            String inputJson =  IOUtils.toString(inputMessage.getBody());
            if(javaType.isCollectionLikeType()
                    && !(inputJson.startsWith("[") && inputJson.endsWith("]")) ) {
                inputJson = "[" + inputJson + "]";
            }
            return getObjectMapper().readValue(inputJson, javaType);
        } catch (IOException ex) {
            throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
        }
    }
}

2. Instantiate that class inside the Spring Servlet configuration file ( Web Pages > WEB-INF > services-servlet.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:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">


    <!--<mvc:annotation-driven/>-->

    <bean class='org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter'>
        <property name='messageConverters'>
            <list>
                <bean class='org.springframework.http.converter.json.CustomMappingJacksonHttpMessageConverter'/>
            </list>
        </property>
    </bean>

    <bean name='handlerMapping' class='org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping'>
        <property name='useTrailingSlashMatch' value='false'></property>
    </bean>

    <!-- ****** REST API Service ****** -->
    <bean id="userService" class="com.extjs.spring.services.UserService" />


    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="mediaTypes">
            <map>
                <entry key="json" value="application/json" />
            </map>
        </property>
        <property name="defaultViews">
            <list>
                <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
                </bean>
            </list>
        </property>
    </bean>


</beans>

3. Add some Apache commons libraries to our pom.xml since are going to be required by our custom converter class.

<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.lvargas</groupId>
    <artifactId>extjs-spring</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>extjs-spring-webapp</name>
    <url>http://maven.apache.org</url>

    <properties>
        <java-version>1.6</java-version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <org.springframework.version>3.2.4.RELEASE</org.springframework.version>
        <org.springframework.security.version>3.2.4.RELEASE</org.springframework.security.version>
        <spring.integration.version>2.2.6.RELEASE</spring.integration.version>
    </properties>

    <dependencies>
        <!-- link to tomcat to get reference to servlet api -->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>servlet-api</artifactId>
            <version>6.0.33</version>
        </dependency>


        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit-dep</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>


        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>apache-log4j-extras</artifactId>
            <version>1.1</version>
        </dependency>




        <!--
                Core utilities used by other modules.
                Define this if you use Spring Utility APIs (org.springframework.core.*/org.springframework.util.*)
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!--
                Bean Factory and JavaBeans utilities (depends on spring-core)
                Define this if you use Spring Bean APIs (org.springframework.beans.*)
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!--
                Aspect Oriented Programming (AOP) Framework (depends on spring-core, spring-beans)
                Define this if you use Spring AOP APIs (org.springframework.aop.*)
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!--
                Application Context (depends on spring-core, spring-expression, spring-aop, spring-beans)
                This is the central artifact for Spring's Dependency Injection Container and is generally always defined
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!--
                Various Application Context utilities, including EhCache, JavaMail, Quartz, and Freemarker integration
                Define this if you need any of these integrations
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!--
                Transaction Management Abstraction (depends on spring-core, spring-beans, spring-aop, spring-context)
                Define this if you use Spring Transactions or DAO Exception Hierarchy
                (org.springframework.transaction.*/org.springframework.dao.*)
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!--
                JDBC Data Access Library (depends on spring-core, spring-beans, spring-context, spring-tx)
                Define this if you use Spring's JdbcTemplate API (org.springframework.jdbc.*)
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!--
                Object-to-Relation-Mapping (ORM) integration with Hibernate, JPA, and iBatis.
                (depends on spring-core, spring-beans, spring-context, spring-tx)
                Define this if you need ORM (org.springframework.orm.*)
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!--
                Object-to-XML Mapping (OXM) abstraction and integration with JAXB, JiBX, Castor, XStream, and XML Beans.
                (depends on spring-core, spring-beans, spring-context)
                Define this if you need OXM (org.springframework.oxm.*)
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!--
                Web application development utilities applicable to both Servlet and Portlet Environments
                (depends on spring-core, spring-beans, spring-context)
                Define this if you use Spring MVC, or wish to use Struts, JSF, or another web framework with Spring (org.springframework.web.*)
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!--
                Spring MVC for Servlet Environments (depends on spring-core, spring-beans, spring-context, spring-web)
                Define this if you use Spring MVC with a Servlet Container such as Apache Tomcat (org.springframework.web.servlet.*)
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>


        <!--
                Support for testing Spring applications with tools such as JUnit and TestNG
                This artifact is generally always defined with a 'test' scope for the integration testing framework and unit testing stubs
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${org.springframework.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>extjs-spring-1.0-SNAPSHOT</finalName>
    </build>
    <description>A maven Archetype to create new EXTJS 4 project powered by a spring MVC 3.2.4 service.</description>
</project>

Finally you can run again and test your project.

Spring Framework Integrated development environment Apache Maven NetBeans

Opinions expressed by DZone contributors are their own.

Related

  • My Experiences with Maven in IntelliJ IDEA and NetBeans IDE
  • Open Source Integration With Apache Camel and How Fuse IDE Can Help
  • Hack OpenJDK with NetBeans IDE
  • Extending Swagger and Spring Doc Open API

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: