All posts by gerrytan

Showing Spring Security Principal and Conditional Logic on JSP

If your app is setup with Spring Security, you can show currently logged in user in JSP by using:

${pageContext.request.userPrincipal.name}

You can also check if the user has enough right to access a resource. This example ensures user has enough rights to access /admin or else the link won’t be rendered:


  
  • Admin Home
  • Make sure you have spring-security-taglibs on your classpath:

    
      org.springframework.security
      spring-security-taglibs
      ${org.springframework.security-version}
    
    

    And the tag prefix declared on top of the JSP page:

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

    AWS EC2 Nginx Reverse Proxy And localhost Slowness

    This is something really odd I yet to fully understand, but for time being I’ve decided using localhost on AWS ec2 is bad. (at least on Windows Server 2008 R2)

    I think it might have something to do with internal DNS or address routing, but my nginx-reverse-proxied tomcat is 4-5x slower when I bind it into localhost as opposed of the local IP. We’re talking 1 minute to load a 300kb css file!

    Open a command prompt and run ipconfig /all and your local ip should be under IPv4 Address under Ethernet adapter Local Area Connection 2:

    ec2-local-ip

    On tomcat, edit your server.xml, find your element and add address attribute:

    
    

    And finally update nginx.conf to point the reverse proxy backend to above IP.

    After doing this now my reverse proxy is much faster, only few seconds to load 300kb css file.

    How To Upload Your Project to Github

    Warning
    Using free Github account will cause your project to be visible publicly

    Often you’re solving a very tricky programming problem and it’s hard to describe it on forum. One very useful thing to do is to isolate the problem by creating a small project and share it. This can be done easily using git and .

    1. Install git if your PC/Mac doesn’t come with one. Use git --version on a terminal shell / command prompt to check.
    2. if you haven’t got one
    3. To avoid having to type in password each time you upload / sync code to github, let’s setup public/private key authentication. This only need to be setup once per PC. First check if you already have a ssh keypair. On windows: open explorer > right click > git bash (or just open a terminal shell on OSX / Linux) > check if you have the file ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub. If you don’t, generate a new one using ssh-keygen (accept all the default setting)
    4. On github . Paste the content of ~/.ssh/id_rsa.pub.
    5. Create new github repository. Give it your project name (eg: foobar).
      github
    6. Back in your computer, point your git shell to the root of your project and run these commands:
      $ git --init
      # You may want to create a .gitignore file before proceeding to
      # next command, see below
      $ git add -A
      $ git commit -m 'initial commit'
      # Change mygitusername and foobar
      $ git remote add origin :mygitusername/foobar.git
      $ git push -u origin master
      

      It’s a good practice to add a .gitignore to avoid tracking binaries and project metadata. Do this before git add -A. This is my typical .gitignore file for a maven java project:

      # All files paths matching these prefix will not be tracked by git
      target
      .settings
      .project
      .classpath
      .springBeans
      
    7. Congratz, you project is now up in github. It’s also a good practice to add a README.md file to include instruction on how to run your project. Run following commands for subsequent changes you want to push to github:
      $ git add -A
      $ git commit -m 'fixed bugs abcd'
      $ git push
      

    Spring Security Auto Login After Successful Registration

    Asking your user to login immediately after he/she registers might be tedious. Here’s how you can log them in immediately using Spring Security (thanks to this SO thread).

    Typically you will have some sort of registration form with a backing controller like this:

    
    ("/register")
    public class RegisterController {
      ...
      (method = POST)
      public String register( User user) {
        // perform registration logic..
        // redirect back to login page
        return "redirect:/login";
      }
      ...
    }
    

    But a server-side login can be done by autowiring UserDetailService and AuthenticationManager:

    
    ("/register")
    public class RegisterController {
      ...
       ("authMgr") private AuthenticationManager authMgr;
       private UserDetailsService userDetailsSvc;
    
      (method = POST)
      public String register( User user) {
        // perform registration logic..
    
        // perform login authentication
        try {
          UserDetails userDetails = userDetailsSvc.loadUserByUsername(username);
          UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
          authMgr.authenticate(auth);
    
          // redirect into secured main page if authentication successful
          if(auth.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(auth);
            return "redirect:/";
          }
        } catch (Exception e) {
          logger.debug("Problem authenticating user" + username, e);
        }
    
        return "redirect:/error";
      }
      ...
    }
    

    Note that in above code the AuthenticationManager injection is qualified by ("authMgr"). This is to avoid multiple beans ambiguity. In effect in the xml context configuration (if you use one) an id attribute has to be set:

      ...
      
        ...
      
    
      
        ...
      
      ...
    

    Also in order for this setup to work, the registration page has to be filtered by spring security

      ...
      
      
    
      
        
      
      ...
    

    See Also

    Installing Spring Security On Spring MVC Project

    IP Whitelisting wp-admin In Nginx

    Similar like Apache, Nginx also has allow & deny directives allowing you to block certain ip. Here’s a config I use to whitelist /wp-admin to certain IP only.

    location / {
      try_files $uri $uri/ /index.php?$args;
    }
    
    location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
      access_log off; log_not_found off; expires max;
    }
    
    location ~ \.php$ {
      try_files                $uri =404;
      fastcgi_pass             localhost:9000;
      fastcgi_index            index.php;
      fastcgi_param            SCRIPT_FILENAME  $document_root$fastcgi_script_name;
      fastcgi_intercept_errors on;
      include                  fastcgi_params;
    }
    
    location ~ ^/wp-(admin|login) {
      allow /32;
      deny  all;
      location ~ \.php$ {
        try_files                $uri =404;
        fastcgi_pass             localhost:9000;
        fastcgi_index            index.php;
        fastcgi_param            SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_intercept_errors on;
        include                  fastcgi_params;
      }
    }
    

    Apart from any path starting with /wp-admin, this will also restrict /wp-login.php to specified IP only.

    Hopefully this come handy when you’re configuring wordpress using nginx php-fpm.

    Using HandlerInterceptor or ControllerAdvice to Make Spring MVC Model Attribute Available Everywhere

    Often you’ll want a particular model attribute to be available everywhere (eg: application version, name, etc). Doing model.addAttribute() everytime is a really bad idea, if you have to refactor it down the track you could end up with hundreds of line modification scattered everywhere.

    Using ControllerAdvice

    One simple way to achieve this as outlined by Spring documentation is by using Spring 3.1′s e annotation.

    Create a new class like this:

    e
    public class PopulateGlobalAttribute {
      ("appversion")
      public String getAppVersion() {
        return "1.0";
      }
    }
    

    And the getAppVersion() will be used to help each handler method in all controllers to add additional stuff to Model object.

    However this method poses one problem. If the handler method is returning a redirect view, the model attributes will be exposed as a query string on the browser URL.

    Using HandlerInterceptor

    Fortunately Josh Kalderimis proposes a nice solution on his blog post using HandlerInterceptor.

    This is my own version of HandlerInterceptor which is based from Josh’s:

    public class PopulateGlobalAttrInterceptor implements HandlerInterceptor {
      private Map properties = new HashMap();
    
      /**
       * This method ensures the global attributes are added only for non-redirection view / view name
       */
      
      public void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler,
          ModelAndView mav) throws Exception {
        if(mav == null) return;
    
        boolean isRedirectView = mav.getView() instanceof RedirectView;
        boolean isViewObject = mav.getView() != null;
        boolean viewNameStartsWithRedirect = (mav.getViewName() == null ? true : 
          mav.getViewName().startsWith(UrlBasedViewResolver.REDIRECT_URL_PREFIX));
        
        if(mav.hasView() && (
          ( isViewObject && !isRedirectView) ||
          (!isViewObject && !viewNameStartsWithRedirect))){
            addCommonModelData(mav);
        }
      }
    
      private void addCommonModelData(ModelAndView mav) {
        mav.getModel().putAll(properties);
      }
    
      
      public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler,
          Exception ex) throws Exception {
      }
    
      
      public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler)
          throws Exception {
        return true;
      }
    
      /* getters & setters */
    }
    

    In SpringMVC HandlerInterceptors are similar like servlet filters, it will be used to filter (intercept) through every requests. Similar like ControllerAdvice, the postHandle method will be invoked by all handlers to help populate the model.

    Once you have this you need to register this interceptors. If you use xml based configuration you can do something like this:

    
    
      ...
    
      
    
      
        
          
            
          
        
      
    
      
        
      
      ...
    
    

    Now without any additional code, you’re guaranteed ${appversion} is available everywhere on your jsp view.

    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
    
    

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