Programming Posts

Create a Simple Autocomplete Textfield using Spring MVC, JQuery, EasyAutocomplete and Hibernate

Several weeks ago i got a request from one of my student, Albi Dwi Haryono. He was asking how to create an autocomplete textbox on JSP page using Spring MVC. So i create this tutorial for helping him and who knows, perhaps also helping other people.

First as usual, create a table Test

CREATE TABLE `test` (
  `field1` varchar(40) NOT NULL,
  PRIMARY KEY (`field1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

create a simple maven file which consist of Spring MVC library, json, MySql and Hibernate,

<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.edw</groupId>
    <artifactId>SpringAutoComplete</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>

    <name>SpringAutoComplete</name>

    <properties>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        
        <!-- Spring dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.10.RELEASE</version>
        </dependency> 
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.3.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>4.3.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>4.3.10.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.3.10.RELEASE</version>
        </dependency>  
        
        <!-- json request -->        
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.6.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.6.3</version>
        </dependency>
        
        <!-- log4j -->   
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency> 
        
        <!-- Hibernate -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.1.8.Final</version>
        </dependency>
        
        <!-- MySQL database driver --> 
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.10</version>
        </dependency>
        
        <!-- dbcp2 -->   
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.1.1</version>
        </dependency>
        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <compilerArguments>
                        <endorseddirs>${endorsed.dir}</endorseddirs>
                    </compilerArguments>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.6</version>
                <executions>
                    <execution>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${endorsed.dir}</outputDirectory>
                            <silent>true</silent>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>javax</groupId>
                                    <artifactId>javaee-endorsed-api</artifactId>
                                    <version>7.0</version>
                                    <type>jar</type>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Next is create configuration file, applicationContext.xml, dispatcher-servlet.xml and registering all thos files on web.xml. I wont explain too much here, just see my github pages for a much more detailed code.

As for java files, i have a java bean Test, as representation for table Test

package com.edw.springautocomplete.bean;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "test")
public class Test implements Serializable {

    @Id
    public String field1;

    public String getField1() {
        return field1;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }
}

And finally a simple controller file, for serving default index page, and also for serving json file for autocomplete purpose.

package com.edw.springautocomplete.controller;

import com.edw.springautocomplete.bean.Test;
import java.util.List;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class IndexController {

    @Autowired
    private SessionFactory sessionFactory;
    
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String index() {
        return "index";
    }

    @Transactional
    @RequestMapping(value = "/field1", method = RequestMethod.GET)
    public @ResponseBody List<Test> field1() {
        return sessionFactory.openSession()
                .createQuery("from Test")
                .list();
    }
}

But, the most important file is the jsp page,

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
        
        <link href="https://cdnjs.cloudflare.com/ajax/libs/easy-autocomplete/1.3.5/easy-autocomplete.min.css" rel="stylesheet" type="text/css">
        <script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/easy-autocomplete/1.3.5/jquery.easy-autocomplete.min.js" type="text/javascript" ></script>
        
    </head>
    <body>
        <input id="field1"/>
        
        <script>
        var options = {
                url: "${pageContext.request.contextPath}/field1",
                getValue: "field1",
                list: {
                        match: {
                                enabled: true
                        }
                }
        };
        $("#field1").easyAutocomplete(options);
        </script>
    </body>
</html>

The result would be like this,
autcomplete1

For the complete sourcecode, can be downloaded here.

Google+

Error Starting JBOSS EAP, Service is already registered

Got a weird error today when deploying a new war to an existing jboss eap environment, it is said that my url is already registered. Here is the complete stacktrace,

2017-10-24 18:47:49,721 ERROR [org.jboss.as.controller.management-operation] (External Management Request Threads -- 1) WFLYCTL0013: Operation ("add") failed - address: ([("deployment" => "my-local-1.0.0-20171024.1141.war")]) - failure description: {
    "WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"my-local-1.0.0-20171024.1141.war\".INSTALL" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"my-local-1.0.0-20171024.1141.war\".INSTALL: WFLYSRV0153: Failed to process phase INSTALL of deployment \"my-local-1.0.0-20171024.1141.war\"
    Caused by: org.jboss.msc.service.DuplicateServiceException: Service jboss.undertow.deployment.default-server.default-host./.session is already registered"},
    "WFLYCTL0412: Required services that are not installed:" => ["jboss.deployment.unit.\"my-local-1.0.0-20171024.1141.war\".INSTALL"],
    "WFLYCTL0180: Services with missing/unavailable dependencies" => undefined
}

2017-10-24 18:47:49,723 ERROR [org.jboss.as.server] (External Management Request Threads -- 1) WFLYSRV0021: Deploy of deployment "my-local-1.0.0-20171024.1141.war" was rolled back with the following failure message:
{
    "WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"my-local-1.0.0-20171024.1141.war\".INSTALL" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"my-local-1.0.0-20171024.1141.war\".INSTALL: WFLYSRV0153: Failed to process phase INSTALL of deployment \"my-local-1.0.0-20171024.1141.war\"
    Caused by: org.jboss.msc.service.DuplicateServiceException: Service jboss.undertow.deployment.default-server.default-host./.session is already registered"},
    "WFLYCTL0412: Required services that are not installed:" => ["jboss.deployment.unit.\"my-local-1.0.0-20171024.1141.war\".INSTALL"],
    "WFLYCTL0180: Services with missing/unavailable dependencies" => undefined
}

The error is actually located on my jboss-web.xml, im deploying 2 war files which have the same context-root url. Changing the deployed war’s context url solve this problem.

<jboss-web>
    <context-root>/</context-root>
</jboss-web>
Google+

Gagal Git Merge di Netbeans

Beberapa kali selalu gagal merge di netbeans, dan somehow git flow di netbeans tidak begitu intuitif terkait hal ini. Walaupun sudah di merge di netbeans, namun sepertinya selalu gagal untuk push ke server. Workaroundnya adalah seperti ini, buka command prompt lalu jalankan command ini.

Simpan perubahan ke branch lain,

git stash

Tarik perubahan dari server,

git pull 

Implementasikan hasil branch keatas hasil pull,

git stash pop
Google+

Importing Swagger API Into Postman

There is one feature that i like the most from Postman, is the ability to import apis from Swagger API directly. On this example, im using two most popular Swagger generator, Springfox and swagger-jaxrs. Basically, this is how you do it,

First need to click on button import on the top of Postman,
postman 1

Next is, selecting import from link,
postman 2

And paste your Swagger documentation url on that textbox, url for Springfox is like this “http://(urlname)/v2/api-docs”, and on Swagger-jaxrs is on “http://(urlname)/api/swagger.json”.

:-D

Google+

HTTP 1.1 vs HTTP 2.0 Performance Comparison on API Service

I’ve had a complex requirement on current project, that is moving all my API services from HTTP 1.1 to HTTP 2.0. Based on the several articles online that i found after googling, it seems that HTTP 2.0 is much faster compared to HTTP 1.1, but that metrics shows browser based request only. Doesnt exactly represent my current condition, which is a native mobile application firing HTTP API request.

So in order to measure performance of both HTTP version, i install two instance of Apache Tomcat 9.0M22 which provides HTTP 1.1 and HTTP 2.0, and create a simple test unit using curl to fetch an image which located on both instance.

Here is the curl that i used to fetch image using HTTP 1.1

curl -I http://128.199.177.158:8080/Sweet-Bites,-Greentea-Brownies-with-Cashew-Ovomaltine-banner1.png

And here is curl for HTTP 2.0

curl -I --http2 https://128.199.177.158:8443/Sweet-Bites,-Greentea-Brownies-with-Cashew-Ovomaltine-banner1.png -k

Fire my unit test for 500 times, and measure the result. Here is the complete graphic

image002

It seems that for fetching a plain image, HTTP 1.1 took less time compared to HTTP 2.0. Perhaps due to my HTTP 1.1 requests are using an insecure connection, while HTTP 2.0 enforcing an SSL connection.

Feel free to look at my code here,


https://github.com/edwin/http2test

It seems that for my case, HTTP 2.0 not yielding a better performance compared to HTTP 1.1. So i guess i’ll stick with HTTP 1.1 for a while.

Google+