Tag Archives: spring

Stock Ticker Demo Webapp Using Spring 4 Websocket

In case you haven’t heard what Websocket is, long story short it’s a brand new cool technique of asynchronous client-server communication for web application. Instead of periodic / long ajax polling, newer browsers allow you to have a persistent socket (almost like TCP) where both client and server can send messages anytime.

Yes the all-new Spring 4 came with shiny Websocket support! Here’s a stock ticker app to get you started (thanks to raymondhlee’s article for the inspiration). This app will let you add/remove a stock code and update its price every second (by randomly adding / subtracting some percentage)

stockticker

Environment / Tools

  • Java 7
  • Tomcat 7.0.47
  • Servlet API 3
  • Spring Framework 4.0.2.RELEASE

Maven Dependencies

Most dependencies are similar to Spring MVC but there’s few addition required to support websocket. You also need to use Servlet 3.


  org.springframework
  spring-context
  ${org.springframework-version}



  org.springframework
  spring-webmvc
  ${org.springframework-version}



  org.springframework
  spring-messaging
  ${org.springframework-version}



  org.springframework
  spring-websocket
  ${org.springframework-version}



  javax.servlet
  javax.servlet-api
  3.1.0
  provided



  com.fasterxml.jackson.core
  jackson-databind
  2.3.2

web.xml

You need to use version 3 of the web.xml schema, and on DispatcherServlet config, set true. Here’s src/main/webapp/WEB-INF/web.xml




  
  
    appServlet
    org.springframework.web.servlet.DispatcherServlet
    
      contextConfigLocation
      /WEB-INF/servlet-context.xml
    
    1
    true
  

  
    appServlet
    /
  


Setup Websocket Message Broker On Servlet Context XML

Apart from the standard Spring MVC config, one new stuff we’re introducing is the Websocket Message Broker. The message broker will help us listening, mapping and sending messages. Note that as suggested by Spring docs we’re using STOMP message protocol and SockJS to support non-websocket browser.

Also note following configs:

  • Stomp endpoint: /ws
  • Message broker app prefix: /app
  • Message queue prefix: /topic

Here’s src/main/webapp/WEB-INF/servlet-context.xml:




  

  

  
    
    
  

  

  
    
      
    
    
  


The Domain Object

Stock class is a simple POJO with code, price and time fields. I’ve also added getTimeStr() to format the time as string and additional constructor.

package com.gerrydevstory.stockticker;

import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Stock implements Serializable {

  private static final long serialVersionUID = 1L;
  private String code = "";
  private double price = 0.0;
  private Date time = new Date();
  
  public Stock() {
    
  }
  
  public Stock(String code, double price) {
    this.code = code;
    this.price = price;
  }
  
  private DateFormat df = new SimpleDateFormat("dd MMM yyyy, HH:mm:ss");
  
  public String getTimeStr() {
    return df.format(time);
  }
  
  /* standard getters & setters */
  
}

Broadcast Prices And Add / Remove Stock

At the core of this app is the HomeController class. There’s a updatePriceAndBroadcast() method which is scheduler to run every 1 second using TaskScheduler. This controller also has websocket handler method to add new stock and remove all. Note the usage of annotation, it will make more sense once we go through the javascript part below.

package com.gerrydevstory.stockticker;


public class HomeController {

   private SimpMessagingTemplate template;  
  private TaskScheduler scheduler = new ConcurrentTaskScheduler();
  private List stockPrices = new ArrayList();
  private Random rand = new Random(System.currentTimeMillis());
  
  /**
   * Iterates stock list, update the price by randomly choosing a positive
   * or negative percentage, then broadcast it to all subscribing clients
   */
  private void updatePriceAndBroadcast() {
    for(Stock stock : stockPrices) {
      double chgPct = rand.nextDouble() * 5.0;
      if(rand.nextInt(2) == 1) chgPct = -chgPct;
      stock.setPrice(stock.getPrice() + (chgPct / 100.0 * stock.getPrice()));
      stock.setTime(new Date());
    }
    template.convertAndSend("/topic/price", stockPrices);
  }
  
  /**
   * Invoked after bean creation is complete, this method will schedule 
   * updatePriceAndBroacast every 1 second
   */
  
  private void broadcastTimePeriodically() {
    scheduler.scheduleAtFixedRate(new Runnable() {
       public void run() {
        updatePriceAndBroadcast();
      }
    }, 1000);
  }
  
  /**
   * Handler to add one stock
   */
  ("/addStock")
  public void addStock(Stock stock) throws Exception {
    stockPrices.add(stock);
    updatePriceAndBroadcast();
  }
  
  /**
   * Handler to remove all stocks
   */
  ("/removeAllStocks")
  public void removeAllStocks() {
    stockPrices.clear();
    updatePriceAndBroadcast();
  }
  
  /**
   * Serve the main page, view will resolve to /WEB-INF/home.jsp
   */
  (value = "/", method = RequestMethod.GET)
  public String home() {
    return "home";
  }

}

Client Side Stuff

To render the stock prices, I created an empty HTML table. The idea is we will empty the table and fill it in with new prices per update


Code Price Time

Underneath that, I’ll also add few form input so you can add a new stock and remove everything

Code: Price:

The javascript stuff is a bit complicated. Apart from JQuery, there are 2 libraries used here: StompJS and SockJS. As opposed of using direct API, SockJS provides fallback for older browser not supporting websocket. StompJS provides higher level abstraction of sending and receiving messages in STOMP protocol.

StompJS did not come with CDN, so I had to manually download it and place it on src/main/webapp/resources/stomp.js




Next is the inline script block. Here I used SockJS to connect to the Spring websocket STOMP endpoint /ws (recall servlet-context.xml above). My webapp context path is /stockticker.

//Create stomp client over sockJS protocol
var socket = new SockJS("/stockticker/ws");
var stompClient = Stomp.over(socket);

// Callback function to be called when stomp client is connected to server
var connectCallback = function() {
  stompClient.subscribe('/topic/price', renderPrice);
}; 

// Callback function to be called when stomp client could not connect to server
var errorCallback = function(error) {
  alert(error.headers.message);
};

// Connect to server via websocket
stompClient.connect("guest", "guest", connectCallback, errorCallback);

The connectCallback function above registers renderPrice callback when a message is sent to /topic/price. This function empties the result HTML table and re-add the cells with new stock price

// Render price data from server into HTML, registered as callback
// when subscribing to price topic
function renderPrice(frame) {
  var prices = JSON.parse(frame.body);
  $('#price').empty();
  for(var i in prices) {
    var price = prices[i];
    $('#price').append(
      $('').append(
        $('').html(price.code),
        $('
').html(price.price.toFixed(2)),
        $('
').html(price.timeStr)
      )
    );
  }
}

              

And lastly, utilising JQuery let’s create handlers for adding and removig stocks

// Register handler for add button
$(document).ready(function() {
  $('.add').click(function(e){
    e.preventDefault();
    var code = $('.new .code').val();
    var price = Number($('.new .price').val());
    var jsonstr = JSON.stringify({ 'code': code, 'price': price });
    stompClient.send("/app/addStock", {}, jsonstr);
    return false;
  });
});

// Register handler for remove all button
$(document).ready(function() {
  $('.remove-all').click(function(e) {
    e.preventDefault();
    stompClient.send("/app/removeAllStocks");
    return false;
  });
});

Download And Try The Source Code

The source code of this demo app . Clone it using git:

git clone .git

Import it as Existing Maven Project in STS (File > Import > Existing Maven Project) and run on in-memory Tomcat 7.0.47 using following Run Configuration (Run > Run Configurations…):

tomcat-22-maven-sts

And this Tomcat container has to run on Java 7 to enable Websocket support.

tomcat-22-maven-sts-jdk

Using SessionAttribute In Spring MVC To Implement A Shopping Cart

Session based shopping cart can be implemented in Spring MVC without much complicated HttpSession read/write. The small web-app we’ll build is like following. The main page will list the cart content plus there’s a form at the bottom allowing you to add new product to the cart:

cart1

First let’s create our Product domain class (don’t forget to make it Serializable since we’ll be storing it in session):

package com.gerrydevstory.shoppingcart;

public class Product implements Serializable {

  private static final long serialVersionUID = 1L;
  
  private String name;
  private double price;
  
  /* getters & setters */  
}

We will define shopping cart as a collection of Product. Here I will simply use an ArrayList to implement my shopping cart. I will utilize Spring MVC’s and e annotation in my controller:

package com.gerrydevstory.shoppingcart;


("/")
es({"cart"})
public class HomeController {

  /**
   * Creates a new cart if one does not exist in session.
   */
  (method = RequestMethod.GET)
  public String get(Model model) {
    if(!model.containsAttribute("cart")) {
      model.addAttribute("cart", new ArrayList());
    }
    return "home";
  }
  
  /**
   * The shopping cart (list of products) is stored in session. Simply inject it using
   * method argument
   */
  (value = "addProduct", method = RequestMethod.POST)
  public String addProduct( Product product,
      ("cart") List cart) {
    cart.add(product);
    return "redirect:/";
  }

}

The trick here is there are 2 important things happening every time a handler method is invoked. First Spring will attempt to populate the model from session (if one not already provided in the request). And when the handler method exits, the attributed will be saved to session.

And finally the JSP form to list and add the product:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>


Shopping Cart


  

Your Shopping Cart

Name: ${product.name}, Price:

Add Product

Name: Price:

Try The Source Code

The source code of this demo is :

git clone https:///gerrytan/shoppingcart.git

Creating a Minimal Spring MVC, JPA / Hibernate and MySQL Project

The goal of this article is to create a bare minimum Spring MVC project with JPA (with Hibernate provider) as persistence provider and MySQL as the DBMS. To test everything works I’ll also add a form page allowing you to list all entities and add a new one.

Environment:

  • jdk 6
  • Spring 3.2.8.RELEASE
  • Hibernate 4.3.3.Final
  • STS 3.4.0.RELEASE
  • MySQL database running on localhost port 3306. The database name is hello with username root and no password.

Steps:

  1. From STS, create a new Maven Project. Since we’re starting from scratch, tick Create a simple project (skip archetype selection). Hit Next.
    jpaminimal0
  2. On the next New Maven Project dialog that comes up, give it a group id, artifact id and set the packaging to war. A minimal maven project will be setup for you when you hit Finish
  3. The default maven project is setup to use jdk 1.5, to switch it to 1.6, open pom.xml and add following xml section under the element.
    
      
        
          maven-compiler-plugin
          
            1.6
            1.6
          
        
      
    
    

    Right click the project on Package Explorer -> Maven -> Update Project.. once this is done to update the eclipse build path into jdk 1.6

  4. Add maven dependencies for Spring, JPA, Hibernate, Java EE, MySQL and other supporting jars. Again this goes to your pom.xml

    
      
      
        org.springframework
        spring-context
        3.2.8.RELEASE
      
    
      
        org.springframework
        spring-webmvc
        3.2.8.RELEASE
      
    
      
        org.springframework
        spring-orm
        3.2.8.RELEASE
      
    
      
      
        org.hibernate
        hibernate-core
        4.3.3.Final
      
    
      
        org.hibernate
        hibernate-entitymanager
        4.3.3.Final
      
    
      
      
        javax.servlet
        servlet-api
        2.5
        provided
      
    
      
        javax.servlet.jsp
        jsp-api
        2.1
        provided
      
    
      
        javax.servlet
        jstl
        1.2
      
    
      
      
        mysql
        mysql-connector-java
        5.1.29
      
    
      
        commons-dbcp
        commons-dbcp
        1.4
      
    
      
        xerces
        xercesImpl
        2.11.0
      
    
    
  5. Create the web deployment descriptor src/main/webapp/WEB-INF/web.xml. We will setup Spring MVC here with bean context configuration xml file set to /WEB-INF/spring-context.xml
    
    
      
      
        appServlet
        org.springframework.web.servlet.DispatcherServlet
        
          contextConfigLocation
          /WEB-INF/spring-context.xml
        
        1
      
      
      
        appServlet
        /
      
    
    
  6. Create a Spring Bean Configuration File placed on src/main/webapp/spring-context.xml. There are plenty important setups here including annotation-based MVC controller, view resolver, transaction config, data source, entityManagerFactory and transaction manager.
    
    
    
      
      
      
      
      
      
      
      
        
        
      
      
      
      
        
        
        
        
      
      
      
      
        
        
      
      
      
      
        
      
      
      
      
    
    
    
  7. Create src/main/resources/META-INF/persistence.xml. This is the persistence unit configuration. It tells JPA what provider will be used, persistence unit type and hibernate configs.
    
    
    
      org.hibernate.ejb.HibernatePersistence
        
            
            
            
            
        
      
    
    
  8. Create a simple entity class to test our setup. Let’s call this entity Person. It has an id and name field.

    package hello;
    
    
    (name = "person")
    public class Person {
    
      @Id
      
      private int id;
    
      private String name;
      
      /* getters & setters */
    
    }
    
  9. And setup mysql database and table to store this entity. The table columns correspond to the Person class fields above. Also note we inform JPA of mysql AUTO_INCREMENT by using annotation:

    CREATE DATABASE IF NOT EXISTS hello;
    
    USE hello;
    
    CREATE TABLE person (
      id INT PRIMARY KEY AUTO_INCREMENT,
      name VARCHAR(50)
    );
    
  10. Create a simple service to list all and add a Person entity

    package hello;
    
    
    public class PersonService {
      
      // An EntityManager will be automatically injected from EntityManagerFactory setup on
      // spring-context.xml
      ext
      private EntityManager em;
      
      // Since we've setup  and transaction manager on spring-context.xml,
      // any bean method annotated with  will cause Spring to magically call
      // begin() and commit() at the start/end of the method. If exception occurs it will also
      // call rollback()
      
      public List getAll() {
        List result = em.createQuery("SELECT p FROM Person p", Person.class).getResultList();
        return result;
      }
      
      
      public void add(Person p) {
        em.persist(p);
      }
    }
    
  11. Create a HomeController class to map HTTP requests. The package name I used is hello:
    package hello;
    
    
    ("/")
    public class HomeController {
    
       private PersonService personSvc;
      
      /**
       * Requests to http://localhost:8080/hello will be mapped here.
       * Everytime invoked, we pass list of all persons to view
       */
      (method = RequestMethod.GET)
      public String listAll(Model model) {
        model.addAttribute("persons", personSvc.getAll());
        return "home";
      }
      
      /**
       * POST requests to http://localhost:8080/hello/addPerson goes here.
       * The new person data is passed from HTML from and bound into the
       * Person object.
       */
      (value = "/addPerson", method = RequestMethod.POST)
      public String addPerson( Person person) {
        personSvc.add(person);
        return "redirect:/";
      }
    }
    
  12. Finally add the form jsp file located on src/main/webapp/WEB-INF/home.jsp
    <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    
    
    
    
    Hello
    
    
      

    All Persons

    Id: ${p.id} Name: ${p.name}

    Add New

    Name:

    This is a simple form which will list all persons and allow you to add one

    Screen Shot 2014-03-03 at 9.51.39 pm

Check Out The Source

You can browse / clone the source code of this article on github. To run this on STS:

  1. Clone it using git
    git clone :gerrytan/jpaminimal.git
  2. On STS, do File > Import > Existing Maven Projects
  3. Create run configuration (Run > Run Configurations…) like this
    mvn-run-config
  4. Make sure the project is selected on the project explorer and run it. This will fire up in-memory tomcat7 server at http://localhost:8080

Spring xercesImpl SAXParseException Problem

Found a really tricky and obscure problem. Whenever running my Spring MVC project it fail at startup with this exception:

org.xml.sax.SAXParseException: cos-all-limited.1.2: An ''all'' model group must appear in a particle with '{'min occurs'}'='{'max occurs'}'=1, and that particle must be part of a pair which constitutes the '{'content type'}' of a complex type definition.

Thanks to this Graham Hacking’s blog article, I figured out this was because commons-dbcp pulling and older version of xercesImpl.

The solution was to add newer version of xercesImpl on pom:


  xerces
  xercesImpl
  2.11.0

Debugging Maven Unit Test in Eclipse / STS

Maven unit tests (run by surefire plugin) can be debugged with eclipse. Firstly check you’re using surefire plugin version 2.16 or newer. Observe / add following in your pom.xml


  maven-surefire-plugin
  2.16

Ensure you’ve set some breakpoints to debug the faulty codes. Then on your run configuration, add -Dmaven.surefire.debug=true parameter:

maven-debug1

When this run configuration is executed, maven will wait for you to attach the remote debugger instead of launching the tests:

maven-debug2

Now open eclipse debug configuration, create a Remote Java Application config with your source code and set the port to 5005:

maven-debug3

When the debugger attaches the unit test will proceed and when any breakpoints hit you can debug it like a normal java/eclipse application

Java and XML Injectable Properties on Spring

Here’s how you can create a property file which can be injected on Java classes as well as on bean XML configuration file.

Firstly ensure annotation config is switched on:

Create your properties file, in this case I create config.properties on my classpath root (src/main/resources/config.properties on Maven-compliant project)

name=Gerry

Register this property file on your spring context using tag.


Whenever you want to inject the value into a Java class, you can use annotation


public class Person {

  ("${name}")
  private String name;

  //...
}

This will only work if your java beans are scanned by the same Spring context. If on different context you will need to create a separate property placeholder

Similarly you can do the same to xml bean config file


  

Multiple Environment Trick

If the value of your configuration item differ accros multiple environments (JDBC URL and context path are a good example of these), you can use the same method to inject value form environment variable.

Returning JSON View on Spring MVC

Another simple way to return JSON object is by using jackson-mapper-asl. Similar to how we can map server-bound post, this method can also be used to write response.

Firstly, on your Spring MVC enabled project, add following maven dependency:


  org.codehaus.jackson
  jackson-mapper-asl
  1.9.12

Spring can automatically convert your POJO into a json string. So say we have this data object we want to return:

public class Customer {
  private String name = "";
  private String email = "";
  // getters & setters...
}

And this is the controller request mapping method. Important bits here is the method returns a POJO object directly, and it is annotated with annotation.

("/customer/{id}")

public Customer getCustomer(("id") long id) {
  Customer customer = // Search customer by given id through repository..
  return customer;
}

On the client side the returned JSON will be something like this:

{
  name = "Tom",
  email = ""
}

Injecting Properties to Spring MVC JSP View

Spring MVC internationalization (i18n) message support can be used for a simple config / property file. Add following bean definition on your container xml config file:


The bean above will read properties key-value pairs from WEB-INF/i18n/site.properties. Make sure you create this file with standard java-style properties:

site.name=Cool Bananas

Then in your JSP views, without any further intervention you can inject the values. Use spring message tag to achieve this

<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>

  
    <message code="site.name"></message>
  
  
  

Binding a List Request Parameter on Spring MVC

Here’s another handy stuff I found on Spring MVC, if you have an unknown number of elements on your form (say a fruit basket), you can bind them into a List with annotation.

Let’s say this is our form:
spring-bind-list

Each text input has the same name fruits:


Fruit 1:
Fruit 2:
Fruit 3:

On your controller’s handler method, you can obtain the list of all fruit names by binding it like this:

(value = "/", method = RequestMethod.POST)
public String addFruits(("fruits") List fruits) {
  // ...
}

The order of fruit names added to the list will be the same as the order of your form text inputs.

Spring Basic Concept: Inversion of Control and Dependency Injection

If you’re a newbie just starting to learn Spring, or even if you’ve heard a lot about Spring but not sure what it was, Martin Fowler has an excellent article about this: Inversion of Control and Dependency Injection pattern.

It was a bit old (written in 2004) but every single conceptual discussion still applies today.

If any of the following keyword doesn’t make any sense to you, then I beg you spare 20 minutes of your time to read this excellent article:

  • Inversion of Control
  • Dependency Injection
  • Service Locator

Gerry's software development journey of trial, errors and re-trials