Table of Contents

Aside

Spring MVC
index-icon-mvc1
Spring MVC Config
Submitting a Form
Multiple Row Form Submit
Radio Button and Check Box
Screen Transition (With More than one Controllers)
Select Box Stays Selected

DI (Dependency Injection) and AOP (Aspect Oriented Programming)
index-icon-mvc-aop1
Overview (Dependency Injection)
Dependency Injection: Setter Injection
Dependency Injection: Field Injection
AOP/Aspect-J Overview and Config
Before Advise
After Advise
Around Advise

JPA Hibernate with Spring MVC
hiv-db-bean-img2
Spring + Hibernate Config
Generic DAO
Generic DAO with Custom Method
Generic DAO without Custom Method
HQL and Native SQL in Hibernate
One to Many – Composite Primary Key
Many to Many
Applying Many to Many

Ajax/jQuery with Spring MVC
hdr-sq-img-ajax2
HTML Table Creation
Radio Button Events
Updating an MVC Partial View
Dynamically Creating a Select Box
To Leverage On-Change Dropdown
Auto Complete

Mongo DB, Web Service, Design Pattern, Data Structure, and Bonus
hdr-sq-img-webservice-img2
Mongo DB + Spring MVC
Mongo Repository
Web Service
Optimizing SQL
Static Factory Pattern
Hash Set vs Array List
How To Work on GitHub

AOP/Aspect-J Overview and Config

aop-image-1
(1) Overview

AOP (Aspect Oriented Programming) is one of key features in Spring framework beside (DI).
In AspectJ, which is more flexible and powerful compared to Spring AOP, There are following advices are available: (Source Code)


(2) Configure

<annotation-driven />
<context:component-scan base-package="com.ns.spring" />

<!-- AOP -->
<aop:aspectj-autoproxy>
    <aop:include name="aopBefore" />
    <aop:include name="aopAfter" />
    <aop:include name="aopAround" />
</aop:aspectj-autoproxy>

<!-- "id": Unique ID used by programs to identify the class. Unlike "name"  -->
<!--       it cannot be more than one reference from the same Java object   -->
<!-- "prototype": New instance each time when called                        -->
<!-- "singleton": Single instance per Spring IoC container                  -->
<beans:bean id="aopBefore"  class="com.ns.spring.aop.advise.AspectBefore" scope="prototype"/>
<beans:bean id="aopAfter"   class="com.ns.spring.aop.advise.AspectAfter"  scope="prototype"/>
<beans:bean id="aopAround"  class="com.ns.spring.aop.advise.AspectAround" scope="prototype"/>

   <properties>
.
      <org.aspectj-version>1.7.4</org.aspectj-version>
   </properties>
   <dependencies>
.
.
.
      <!-- AspectJ -->
      <dependency>
         <groupId>org.aspectj</groupId>
         <artifactId>aspectjrt</artifactId>
         <version>${org.aspectj-version}</version>
         <scope>runtime</scope>
      </dependency>
      <dependency>
         <groupId>org.aspectj</groupId>
         <artifactId>aspectjtools</artifactId>
         <version>${aspectj.version}</version>
      </dependency>
      <dependency>
         <groupId>org.aspectj</groupId>
         <artifactId>aspectjweaver</artifactId>
         <version>1.8.5</version>
      </dependency>
      <dependency>
         <groupId>cglib</groupId>
         <artifactId>cglib</artifactId>
         <version>2.2.2</version>
      </dependency>
   </dependencies>
</project>

MongoDB + Spring MVC

mongodb-img3
NoSQL (Not Only SQL) is growing beside a RDB (Relational database). For example, DynamoDB for Amazon, BigTable for Google, Apollo for Facebook, and so forth. MongoDB is the one of most popular NoSQL DB.


Overview

  • It is said to be “Documente Oriented”, and they call table as “Collection”.
  • Unlike RDB, it does not support JOIN.
  • It Supports an ARRAY in a single record (document).
  • The format looks like JSON object. Therefore, it is good to use with Web Service.
  • Mongo DB is written in C++

This example is Spring MVC with CRUD operation by Mongo DB to demonstrate Web Service. And here is the configuration:
mongo-config

<!-- Mongo DB -->
<dependency>
	<groupId>org.springframework.data</groupId>
	<artifactId>spring-data-mongodb</artifactId>
	<version>1.5.2.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.mongodb</groupId>
	<artifactId>mongo-java-driver</artifactId>
	<version>2.12.4</version>
</dependency>

<dependency>
	<groupId>com.drewnoakes</groupId>
	<artifactId>metadata-extractor</artifactId>
	<version>2.4.0-beta-1</version>
</dependency>

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>ns2015mvcmongo001</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

    <servlet>
        <servlet-name>ns2015</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>ns2015</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

NOTE: At line 16 of web.xml, servlet-name is specified as ns2015. Therefore, servlet context file will be “ns2015-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:context="http://www.springframework.org/schema/context"
    xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    xsi:schemaLocation="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-4.0.xsd
        http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.5.xsd">

	<context:component-scan base-package="com.ns.spring" />
	 
	<!-- Configuration defining views files -->	 
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	    <property name="prefix">
	        <value>/WEB-INF/jsp/</value>
	    </property>
	    <property name="suffix">
	        <value>.jsp</value>
	    </property>
	</bean>
	 
	<!-- Factory bean that creates the Mongo instance -->
	<bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
	    <property name="host" value="localhost" />
	</bean>
	 
	<!-- MongoTemplate for connecting and quering the documents in the database -->
	<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
	     <constructor-arg name="mongo" ref="mongo" />
	     <constructor-arg name="databaseName" value="nsdb" />
	</bean>

	<!-- To scan sub interface for MongoRepository -->
	<mongo:repositories base-package="com.ns.spring" />
</beans>

How To Work on GitHub

github-hdr-img1
This used to be my personal memo to work on GitHub (basic operation), but I also thought it’s good to share to others who might have the same (or similar) problem.

Summary:

  • Creating Repository
  • How to clone the repository
  • How to upload your resource
  • GitHub website to add a SSH key
  • How to generating a SSH key
  • How to delete repository

Web Service

title-image-ws7
In large organization, it can be common to share the data between different systems.

For example, the first system get the “Not authorized transactions” from the other system, and authorize them.

This example shows communicating two different websites through Web Service. The each website uses the different Database. Moreover, they are different kind of database; RDB and NoSQL DB.

They are completely different system but they can share the same data.
webservice-flow-img2

Website 1:

  • URL: http://localhost:8080/ns2015mvcmongo001
  • DB: Mongo DB
  • Send a request to Website 2, and received the response (JSON) and store them in Mongo DB.

Website 2:

  • URL: http://localhost:8080/NS2015V07
  • DB: My SQL
  • Receive the request from Website 1, and get the data from DB (My SQL) and send a response (JSON object) back to Website 1.

2015-06-06_21h23_52


Summarized (Three steps) as two websites are communicating through HTTP:

  1. The Website 1 request the Return transactions (RMAs) which are not “Authorized” to Website 2.
  2. The Website 2 response to the Website 1 with the transactions (in JSON object)
  3. The Website 2 stored them in Mongo DB

From: http://localhost:8080/ns2015mvcmongo001/welcome_01.html
file_MVCController_img2
Controller (Website 1) calls Request to (Website 2):

<input type="submit" value="WebService" name="webService" />

Button in JSP

@RequestMapping(value = "/welcome_01", params = "webService", method = RequestMethod.POST)
public ModelAndView refreshByWebService() {	
	ModelAndView modelAndView = new ModelAndView("welcome_01");	
	List<JSONObject> jsonList = getRmaHdrList();
	saveRma(jsonList);

	List<RMA_HDR> rmaList = rmaRep.findByRma_exclude("auth");
	modelAndView.addObject("rmaList", rmaList);

	return modelAndView;
}

Step 1.1. Calls “getRmaHdrList()” method

private List<JSONObject> getRmaHdrList() {
	String output = getJsonStrByURL(this.url);
	List<JSONObject> list = new ArrayList<JSONObject>();
	try {
		JSONParser parser = new JSONParser();
		Object obj = parser.parse(output);
		JSONArray array = (JSONArray) obj;
		
		for (int i = 0; i < array.size(); i++) {
			JSONObject json = (JSONObject) array.get(i);
			list.add(json);

			Long id = (Long) json.get("id");
			String rmaNum = (String) json.get("rmaNum");
			String rmaHdrStsCd = (String) json.get("rmaHdrStsCd");

			System.out.println("id: " + id);
			System.out.println("rmaNum: " + rmaNum);
			System.out.println("rmaHdrStsCd: " + rmaHdrStsCd);
		}
	} catch (Exception e) {
		e.printStackTrace();
	}		
	return list;
}

Step 1.2. Calls “getJsonStrByURL(String url)” method

private String getJsonStrByURL(String url) {
	Client client = Client.create();
	WebResource response = client.resource("http://localhost:8080/NS2015V07/ns-home/json");
	ClientResponse clientRes = response.accept("application/json").get(ClientResponse.class);
	if (clientRes.getStatus() != 200) {
		throw new RuntimeException("Failed : HTTP error code : " + clientRes.getStatus());
	}
	return clientRes.getEntity(String.class);
}

Step 1.3. Calls Website 2: “http://localhost:8080/NS2015V07/ns-home/json”


From: http://localhost:8080/NS2015V07/ns-home/json
file_WSController_img2
Controller in Website 2 received a request and send a response back to Website 1:

@RequestMapping(value = "/ns-home/json", method = RequestMethod.GET)
public @ResponseBody List<RmaHdrModel> getAll(HttpServletRequest req) {
	List<RmaHdrModel> list = RmaBL.getRmaHdrListWCdTblNm(req);
	List<JSONObject> entities = new ArrayList<JSONObject>();
	for (RmaHdrModel rma : list) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("id", rma.getId());
		jsonObject.put("rmaNum", rma.getRmaNum());
		jsonObject.put("rmaHdrStsCd", rma.getRmaHdrStsCd());
		entities.add(jsonObject);
	}
	return list;
}

Step 2.1. At line 3, get the record from DB (MySQL).
Step 2.2. At line 6 to 10, create a JSON object and being set to a list.
Step 2.3. At line 12, return a list (JSON) as a response to: http://localhost:8080/ns2015mvcmongo001/welcome_01.html

Mongo Repository

mongodb-img3
For CRUD operation in Mongo DB, you have basically two choices:

  • MongoTemplate
  • MongoRepository

And MongoRepository is said to be more advanced compared to MongoTemplate. MongoTemplate provide more pre-defined method than MongoRepository, but MongoRepository is very much like Generic DAO. There are some pre-defined method but you can define your custom methods.

2015-06-05_08h32_07

package com.ns.spring.dao;

import java.util.List;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import org.springframework.data.mongodb.repository.Query;
import com.ns.spring.model.RMA_HDR;


@Repository
public interface RmaHdrRepository extends MongoRepository<RMA_HDR, String>{
	
	@Query("{rma_num : ?0}")
	List<RMA_HDR> findByRma_num(String rma_num);

	@Query("{rma_hdr_sts_cd : ?0}")
	List<RMA_HDR> findByRma_hdr_sts_cd(String findByRma_hdr_sts_cd);
	
	@Query("{'rma_hdr_sts_cd' : {$ne : ?0}}")
	List<RMA_HDR> findByRma_exclude(String findByRma_hdr_sts_cd);
	
}

The syntax for MongoDB statements

In MongoDB, the table (RDB) is called “Collection”.
For inquiry: db.”collection name”.find()


Following are some customized generic method defined in RmaHdrRepository.java (line 14 and 20). These will be executed in Mongo DB.

@Query("{rma_num : ?0}")
List<RMA_HDR> findByRma_num(String rma_num);
    /* select * from  rma_hdr where rma_num  = 'RMA00026' */
    db.rma_hdr.find({rma_num : 'RMA00026'})
    

    momgo-select-by-id-img1

@Query("{'rma_hdr_sts_cd' : {$ne : ?0}}")
List<RMA_HDR> findByRma_exclude(String findByRma_hdr_sts_cd);
    /* select * from  rma_hdr where rma_hdr_sts_cd <> 'auth' */
    db.rma_hdr.find({'rma_hdr_sts_cd' : {$ne : 'auth'}})
    

    momgo-select-by-not-eq-img1

NOTE: Equivalent SQL are showing as comments.

List<RMA_HDR> list = rmaRep.findByRma_num(rma_num);
List<RMA_HDR> rmaList = rmaRep.findByRma_exclude("auth");

Called by MVCController.java at line 49, 86 and 96.


Following are non-customized method; Already provided by Mongo Repository

    findAll()
    save(object)
    delete(object)
List<RMA_HDR> rmaList = rmaRep.findAll();
rmaRep.save(rma);
rmaRep.delete(rma);

Called by MVCController.java at line 35, 61, 81, 101, 107.


package com.ns.spring;

import java.util.ArrayList;
import java.util.List;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
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.servlet.ModelAndView;

import com.ns.spring.dao.RmaHdrRepository;
import com.ns.spring.model.RMA_HDR;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;

@Controller
public class MVCController {

	private String url = "http://localhost:8080/NS2015V07/ns-home/json";

	@Autowired
	private RmaHdrRepository rmaRep;

	@RequestMapping(value = "/welcome_01")
	public ModelAndView init01(ModelMap model) {

		ModelAndView modelAndView = new ModelAndView("welcome_01");
		List<RMA_HDR> rmaList = rmaRep.findAll();
		modelAndView.addObject("rmaList", rmaList);

		// mast be match with jsp name to be displayed
		return modelAndView;
	}

	@RequestMapping(value = "/welcome_01", params = "webService", method = RequestMethod.POST)
	public ModelAndView refreshByWebService() {

		ModelAndView modelAndView = new ModelAndView("welcome_01");
		List<JSONObject> jsonList = getRmaHdrList();
		saveRma(jsonList);

		List<RMA_HDR> rmaList = rmaRep.findByRma_exclude("auth");
		modelAndView.addObject("rmaList", rmaList);

		return modelAndView;
	}

	@RequestMapping("/authorize/{rmaNum}")
	public ModelAndView authorizeRma(@PathVariable("rmaNum") String rmaNum) {

		ModelAndView modelAndView = new ModelAndView("welcome_01");
		saveByRmaNum(rmaNum, "auth");

		List<RMA_HDR> rmaList = rmaRep.findAll();
		modelAndView.addObject("rmaList", rmaList);

		return modelAndView;
	}

	private void saveRma(List<JSONObject> jsonList) {

		for (int i = 0; i < jsonList.size(); i++) {
			JSONObject rmaJson = jsonList.get(i);
			Long id = (Long) rmaJson.get("id");
			String rmaNum = (String) rmaJson.get("rmaNum");
			String stsCd = (String) rmaJson.get("rmaHdrStsCd");

			deleteByRmaNum(rmaNum);

			RMA_HDR rma = new RMA_HDR();
			rma.setRma_num(rmaNum);
			rma.setRma_hdr_sts_cd(stsCd);

			rmaRep.save(rma);
		}
	}

	private void deleteByRmaNum(String rma_num) {
		List<RMA_HDR> list = rmaRep.findByRma_num(rma_num);
		if (list != null && list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				RMA_HDR temp = list.get(i);
				delete(temp);
			}
		}
	}

	private void saveByRmaNum(String rma_num, String stsNm) {
		List<RMA_HDR> list = rmaRep.findByRma_num(rma_num);
		if (list != null && list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				RMA_HDR temp = list.get(i);
				temp.setRma_hdr_sts_cd(stsNm);
				rmaRep.save(temp);
			}
		}
	}

	private void delete(RMA_HDR obj) {
		rmaRep.delete(obj);
	}

	private List<JSONObject> getRmaHdrList() {
		String output = getJsonStrByURL(this.url);
		List<JSONObject> list = new ArrayList<JSONObject>();
		try {
			JSONParser parser = new JSONParser();
			Object obj = parser.parse(output);
			JSONArray array = (JSONArray) obj;

			for (int i = 0; i < array.size(); i++) {
				JSONObject json = (JSONObject) array.get(i);
				list.add(json);

				Long id = (Long) json.get("id");
				String rmaNum = (String) json.get("rmaNum");
				String rmaHdrStsCd = (String) json.get("rmaHdrStsCd");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}

	private String getJsonStrByURL(String url) {
		Client client = Client.create();
		WebResource response = client.resource("http://localhost:8080/NS2015V07/ns-home/json");
		ClientResponse clientRes = response.accept("application/json").get(ClientResponse.class);
		if (clientRes.getStatus() != 200) {
			throw new RuntimeException("Failed : HTTP error code : " + clientRes.getStatus());
		}
		return clientRes.getEntity(String.class);
	}
}

Dependency Injection: Setter Injection

di-img2
This is an example of Setter injection, which is most popular method compared to field and constructor injection. A business logic class uses a object of DAO service class.
di-setter-3
di-setter-inj-rma
This is annotation based DI, so you don’t need to specify a bean in XML file but you still need to tell annotation drive to servlet context.

<annotation-driven />
<context:component-scan base-package="com.ns.spring" />

As the line 20 to 24 shows, it will injects the dependency via a setter method. And 28 to 39 shows it usage.

package com.ns.spring.common;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.ns.spring.constant.RtrnConstant;
import com.ns.spring.model.RMA_HDR;
import com.ns.spring.model.ui.RmaHdrModel;
import com.ns.spring.service.template.RmaHdrService;

@Component
public class RmaBL implements RtrnConstant {

	private static RmaHdrService hdrSvc;

	@Autowired(required = true)
	public void setHdrSvc(RmaHdrService hdrSvc) {
		this.hdrSvc = hdrSvc;
	}

	public static List<Object[]> getRmaHdrListObj(String rmaNum) {
		return hdrSvc.getListRmaHdrBySql(rmaNum);
	}

	public static RMA_HDR saveHdr(RmaHdrModel rma, HttpServletRequest req) {
		RMA_HDR obj = new RMA_HDR(rma);
		if (rma.getId() == 0) {
			hdrSvc.save(obj);
			// Set RMA# with formatted
			DecimalFormat df = new DecimalFormat("000000");
			obj.setRmaNum("RMA" + df.format((double) obj.getId()));
		}
		hdrSvc.update(obj);
		req.getSession().removeAttribute(CONST.HDR_LIST.getVal());
		return obj;
	}

	public static RMA_HDR getRmaHdrObj(String rmaNum) {
		List<Object[]> rmaHdrList = getRmaHdrListObj(rmaNum);
		if (!CommonBL.isEmpty(rmaHdrList)) {
			Object[] objArr = rmaHdrList.get(0);
			int id = (Integer) objArr[0];
			return hdrSvc.findById(id);
		}
		return null;
	}
.
.
.
}

Dependency Injection: Field Injection

di-img2
This is a example of field injection, which is very simple. One controller use three different service classes to access data base (DAO service class).
di-fld-3
di-filed-inj-rp-rsn
This is annotation based DI, so you don’t need to specify a bean in XML file but you still need to tell annotation drive to servlet context.

<annotation-driven />
<context:component-scan base-package="com.ns.spring" />

Line 42 to 48 shows the field injection, and 65 to 94 use the object without “new” keyword.

package com.ns.spring;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.ns.spring.common.CommonBL;
import com.ns.spring.common.RmaBL;
import com.ns.spring.common.RsnBL;
import com.ns.spring.common.TpBL;
import com.ns.spring.common.TpRsnBL;
import com.ns.spring.common.gen.BLFactory;
import com.ns.spring.constant.RtrnConstant;
import com.ns.spring.model.RTRN_RSN;
import com.ns.spring.model.RTRN_TP;
import com.ns.spring.model.RTRN_TP_RSN_CMBN;
import com.ns.spring.model.ui.RmaHdrModel;
import com.ns.spring.model.ui.RtrnRsnModel;
import com.ns.spring.model.ui.RtrnTpModel;
import com.ns.spring.service.template.RtrnRsnService;
import com.ns.spring.service.template.RtrnTpRsnService;
import com.ns.spring.service.template.RtrnTpService;

@Controller
public class TpRsnController implements RtrnConstant {

	@Autowired(required = true)
	private RtrnTpService tpSvc;

	@Autowired(required = true)
	private RtrnRsnService rsnSvc;

	@Autowired(required = true)
	private RtrnTpRsnService tpRsnSvc;

	@RequestMapping(value = "/cUrlValAttrbMain01Jsp", params = "goToTpRsn", method = RequestMethod.POST)
	public ModelAndView goToTpRsn(ModelMap model, HttpServletRequest req) {
		return getMVSubTpRsn01(model, req);
	}

	@RequestMapping(value = "/cUrlValAttrbSubTpRsn01Jsp", params = "backToRmaFromTpRsn", method = RequestMethod.POST)
	public ModelAndView backToRmaFromTpRsn(Model model, HttpServletRequest req) {
		return getMVMain01(req);
	}

	@RequestMapping(value = "/cUrlValAttrbSubTpRsn01Jsp", params = "toBoundRsnList", method = RequestMethod.POST)
	public ModelAndView toBoundRsnList(@ModelAttribute("RtrnTpModel") RtrnTpModel tp, ModelMap model, HttpServletRequest req) {

		String tpSelected = (String) req.getSession().getAttribute(CONST.TP_SELECTED.getVal());
		if (CommonBL.hasValue(tpSelected)) {
			RTRN_TP tpObj = this.tpSvc.findById(tpSelected);
			if (tpObj != null) {
				List<String> selectedCheckBox = TpRsnBL.getRsnToBound(tp, req);
				if (!CommonBL.isEmpty(selectedCheckBox)) {
					Set<RTRN_RSN> rtrnRsns = new HashSet<RTRN_RSN>();
					for (String code : selectedCheckBox) {
						RTRN_RSN rsnObj = this.rsnSvc.findById(code);
						if (rsnObj != null) {
							rtrnRsns.add(rsnObj);
							tpObj.setRtrnRsns(rtrnRsns);
							this.tpSvc.saveOrUpdate(tpObj);
						}
					}
				}
			}
		}
		return getMVSubTpRsn01(model, req);
	}

	@RequestMapping(value = "/cUrlValAttrbSubTpRsn01Jsp", params = "toUnBoundRsnList", method = RequestMethod.POST)
	public ModelAndView toUnBoundRsnList(@ModelAttribute("RtrnTpModel") RtrnTpModel tp, ModelMap model, HttpServletRequest req) {

		String tpSelected = (String) req.getSession().getAttribute(CONST.TP_SELECTED.getVal());
		if (CommonBL.hasValue(tpSelected)) {
			List<String> selectedCheckBox = tp.getSelectedCheckBox();
			if (!CommonBL.isEmpty(selectedCheckBox)) {
				for (String code : selectedCheckBox) {
					RTRN_TP_RSN_CMBN tpRsnObj = this.tpRsnSvc.getTpRsnCmbnByHql(tpSelected, code);
					if (tpRsnObj != null) {
						this.tpRsnSvc.delete(tpRsnObj);
					}
				}
			}
		}
		return getMVSubTpRsn01(model, req);
	}

.
.
.

}

Radio Button and Check Box

mvc-template1
In Biz Apps, you almost always need to use Check Box and Radio button.

Check box is to select multiple objects, and radio button is only select one of multiple objects. The reason we call “Radio button” is originally came from Car Radio; It is only let you select one station at a time.
radio-checkbox-img2
In Spring MVC, check box object is usually a list of String, and radio button is Integer. You will defined them in a Model layer (Bean).

There are some examples for Radio Button and Check Box in Biz Apps. Typically, you will used them in a list.

  1. The specified row (by Radio Button) will be updated.
  2. Selected records will be updated/deleted. (Many to Many)
<c:forEach items="${HDR_LIST}" var="rmaObj" varStatus="loop">
	<tr height="15">
		<td><form:radiobutton path="radioBtn" class='close clickIdx' data-id='${rmaObj.id}' /></td>
		<td><form:checkbox path="selectedCheckBox" value="${rmaObj.rmaNum}"/></td>
		<td id="id${loop.index}">${rmaObj.id}</td>
		<td id="idRmaNum${loop.index}">${rmaObj.rmaNum}</td>
		<td id="idStsCd${loop.index}">${rmaObj.rmaHdrStsCd}</td>
		<td id="idStsNm${loop.index}">${rmaObj.rmaHdrStsNm}</td>
		<td id="idTpCd${loop.index}">${rmaObj.rtrnTpCd}</td>
		<td id="idTpNm${loop.index}">${rmaObj.rtrnTpNm}</td>
		<td id="idRsnCd${loop.index}">${rmaObj.rtrnRsnCd}</td>
		<td id="idRsnNm${loop.index}">${rmaObj.rtrnRsnNm}</td>
		<td id="idCustCd${loop.index}">${rmaObj.sellToCustCd}</td>
		<td><a href="<c:url value='/edit/${rmaObj.id}' />" >Edit</a></td>
		<td><a href="<c:url value='/remove/${rmaObj.id}' />" >Delete</a></td>
		<td><a href="<c:url value='/cUrlValSubLine01Jsp/${rmaObj.rmaNum}' />" >Detail</a></td>
	</tr>
</c:forEach>

1. Radio button is defined as integer that will contains a row number
2. Check box is defined as List of String that contains a value of selected record(s)

package com.ns.spring.model.ui;

import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.ns.spring.model.RMA_HDR;

@JsonIgnoreProperties(ignoreUnknown = true)
public class RmaHdrModel {

	private int id;
	private String rmaNum = "";
	private String rmaHdrStsCd = "";
	private String rmaHdrStsNm = "";
	private String rtrnTpCd = "";
	private String rtrnTpNm = "";
	private String rtrnRsnCd = "";
	private String rtrnRsnNm = "";
	private String sellToCustCd = "";
	private String mdseCd = "";
	private List<RmaLineModel> rmaLines = new ArrayList<RmaLineModel>();
	private int radioBtn;
	private List<String> selectedCheckBox = new ArrayList<String>();
	
	public RmaHdrModel(){}

.
.
.
.

	public int getRadioBtn() {
		return radioBtn;
	}

	public void setRadioBtn(int radioBtn) {
		this.radioBtn = radioBtn;
	}

	public List<String> getSelectedCheckBox() {
		return selectedCheckBox;
	}

	public void setSelectedCheckBox(List<String> selectedCheckBox) {
		this.selectedCheckBox = selectedCheckBox;
	}
}

Optimizing SQL

night-job-img1
While you are sleeping, there are lots of programs are running based on it’s scheduling. They are often called “Batch Jobs“. And one of batch jobs is to get rid of old transactions.

In Biz apps, we often need to do performance tuning. According to my experience, the SQL is usually the biggest reason to cause a performance issue.

I have a memory that I have a performance issue for this SQL.
This is to get the target records for Data Purge (Oracle):

SELECT
*
FROM TABLE_TO_BE_PURGED A
WHERE
EXISTS ( 
    SELECT '*' 
    FROM  
          PURGE_TARGET_TABLE TGT
    WHERE 1=1
    AND  TGT.INV_NUM  = A.REF_TXT_01
) OR EXISTS ( 
    SELECT '*' 
    FROM 
          INTEREFACE_TABLE ITFC, 
    PURGE_TARGET_TABLE     TGT 
    WHERE 
         ITFC.REF_NUM     = B.REF_NUM
    AND  ITFC.REF_SUB_NUM = B.REF_SUB_NUM
    AND  ITFC.INV_NUM     = TGT.INV_NUM
) 

And came up with this after struggling hours…

SELECT
*
FROM TABLE_TO_BE_PURGED A1
WHERE EXISTS (
    SELECT '*'
    FROM (
        SELECT 
            B1.PURGED_PK
        FROM 
            TABLE_TO_BE_PURGED  B1
        ,   PURGE_TARGET_TABLE  TGT
        WHERE 1=1
        AND TGT.INV_NUM = B1.REF_TXT_01
        UNION
        SELECT 
            B2.PURGED_PK
        FROM 
            TABLE_TO_BE_PURGED  B2
        ,   INTEREFACE_TABLE    ITFC
        ,   PURGE_TARGET_TABLE  TGT
        WHERE 
            ITFC.REF_NUM     = B2.REF_NUM
        AND ITFC.REF_SUB_NUM = B2.REF_SUB_NUM
        AND ITFC.INV_NUM     = TGT.INV_NUM
    ) T1
    WHERE T1.PURGED_PK = A1.PURGED_PK
)

The performance improved dramatically, but the interesting thing was that the execution plan (cost) was pretty much the same. The one above get slower when having more records. And the one below was fast enough although having many records.