Many to Many

many-to-many-header-img1
Many-to-Many mapping is usually implemented a Join Table, suppose we have Type and Reason table and Reason table for many-to-many mapping. Every Type can have more than one Reasons and every Reasons is a part of more than one Type.
2015-05-17_10h45_40

CREATE TABLE `rtrn_tp` (
	`rtrn_tp_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`rtrn_tp_nm` VARCHAR(100) NULL DEFAULT NULL,
	`sort_num` INT(11) UNSIGNED NOT NULL DEFAULT '0',
	PRIMARY KEY (`rtrn_tp_cd`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
CREATE TABLE `rtrn_rsn` (
	`rtrn_rsn_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`rtrn_rsn_nm` VARCHAR(100) NULL DEFAULT NULL,
	`sort_num` INT(11) UNSIGNED NOT NULL DEFAULT '0',
	PRIMARY KEY (`rtrn_rsn_cd`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
CREATE TABLE `rtrn_tp_rsn_cmbn` (
	`rtrn_tp_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`rtrn_rsn_cd` VARCHAR(20) NOT NULL DEFAULT '',
	PRIMARY KEY (`rtrn_tp_cd`, `rtrn_rsn_cd`),
	INDEX `fk_rtrn_rsn` (`rtrn_rsn_cd`),
	CONSTRAINT `fk_rtrn_rsn` FOREIGN KEY (`rtrn_rsn_cd`) REFERENCES `rtrn_rsn` (`rtrn_rsn_cd`),
	CONSTRAINT `fk_rtrn_tp` FOREIGN KEY (`rtrn_tp_cd`) REFERENCES `rtrn_tp` (`rtrn_tp_cd`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

There is a Join Table, RTRN_TP_RSN_CMBN, only have the relationship between Type (RTRN_TP) and Reason (RTRN_RSN)

package com.ns.spring.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "RTRN_TP")
public class RTRN_TP {

	@Id
	@Column(name = "rtrn_tp_cd")
	private String rtrnTpCd;

	@Column(name = "rtrn_tp_nm")
	private String rtrnTpNm;

	@Column(name = "sort_num")
	private int sortNum;

	@ManyToMany(targetEntity = RTRN_RSN.class, cascade = { CascadeType.ALL })
	@JoinTable(name = "RTRN_TP_RSN_CMBN", 
				joinColumns = { @JoinColumn(name = "rtrn_tp_cd") }, 
				inverseJoinColumns = { @JoinColumn(name = "rtrn_rsn_cd") })
	private Set<RTRN_RSN> rtrnRsns = new HashSet<RTRN_RSN>();

	public String getRtrnTpCd() {
		return rtrnTpCd;
	}

	public void setRtrnTpCd(String rtrnTpCd) {
		this.rtrnTpCd = rtrnTpCd;
	}

	public String getRtrnTpNm() {
		return rtrnTpNm;
	}

	public void setRtrnTpNm(String rtrnTpNm) {
		this.rtrnTpNm = rtrnTpNm;
	}

	public int getSortNum() {
		return sortNum;
	}

	public void setSortNum(int sortNum) {
		this.sortNum = sortNum;
	}

	public Set<RTRN_RSN> getRtrnRsns() {
		return rtrnRsns;
	}

	public void setRtrnRsns(Set<RTRN_RSN> rtrnRsns) {
		this.rtrnRsns = rtrnRsns;
	}

	public String toString() {
		return "Type Code:" + this.rtrnTpCd + ", Name:" + this.rtrnTpNm;
	}
}
package com.ns.spring.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "RTRN_RSN")
public class RTRN_RSN {

	@Id
	@Column(name = "rtrn_rsn_cd")
	private String rtrnRsnCd;
	
	@Column(name = "rtrn_rsn_nm")	
	private String rtrnRsnNm;
	
	@Column(name = "sort_num")	
	private int sortNum;

	public String getRtrnRsnCd() {
		return rtrnRsnCd;
	}

	public void setRtrnRsnCd(String rtrnRsnCd) {
		this.rtrnRsnCd = rtrnRsnCd;
	}

	public String getRtrnRsnNm() {
		return rtrnRsnNm;
	}

	public void setRtrnRsnNm(String rtrnRsnNm) {
		this.rtrnRsnNm = rtrnRsnNm;
	}

	public int getSortNum() {
		return sortNum;
	}

	public void setSortNum(int sortNum) {
		this.sortNum = sortNum;
	}

	public String toString() {
		return "Reason Code:" + this.rtrnRsnCd + ", Name:" + this.rtrnRsnNm;
	}
}
package com.ns.spring.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

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

	private static final long serialVersionUID = 4677612728077605784L;

	@Id
	@Column(name = "rtrn_tp_cd")
	private String rtrnTpCd;
	
	@Id
	@Column(name = "rtrn_rsn_cd")
	private String rtrnRsnCd;
	
	public String getRtrnTpCd() {
		return rtrnTpCd;
	}

	public void setRtrnTpCd(String rtrnTpCd) {
		this.rtrnTpCd = rtrnTpCd;
	}

	public String getRtrnRsnCd() {
		return rtrnRsnCd;
	}

	public void setRtrnRsnCd(String rtrnRsnCd) {
		this.rtrnRsnCd = rtrnRsnCd;
	}
	
	public String toString() {
		return "Type" + this.rtrnTpCd + ", Reason:" + this.rtrnRsnCd;
	}
}
@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);
}

This is how to use Many to Many in Spring MVC.

One to Many – Composite Primary Key

one-to-many-header-img1
In Hibernate, you need to have special field in order to accomplish a composite primary key to make it as a single key object:
one-to-many-header-comppk1
To handle composite primary key, you need to user an extra class “RmaLinePk”.
2015-06-01_07h41_10

2015-05-17_10h08_28

CREATE TABLE `rma_hdr` (
	`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
	`rma_num` VARCHAR(20) NOT NULL DEFAULT '',
	`rma_hdr_sts_cd` VARCHAR(20) NULL DEFAULT NULL,
	`rtrn_tp_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`rtrn_rsn_cd` VARCHAR(20) NULL DEFAULT NULL,
	`sell_to_cust_cd` VARCHAR(20) NULL DEFAULT NULL,
	PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=27
;
CREATE TABLE `rma_line` (
	`rma_num` VARCHAR(20) NOT NULL DEFAULT '',
	`rma_line_num` VARCHAR(20) NOT NULL DEFAULT '',
	`rma_line_sts_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`mdse_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`qty` INT(11) UNSIGNED NOT NULL DEFAULT '0',
	`rma_id` INT(11) UNSIGNED NOT NULL,
	PRIMARY KEY (`rma_num`, `rma_line_num`),
	INDEX `rma_id` (`rma_id`),
	CONSTRAINT `rma_line_ibfk_1` FOREIGN KEY (`rma_id`) REFERENCES `rma_hdr` (`id`) ON DELETE CASCADE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
package com.ns.spring.model;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import com.ns.spring.model.ui.RmaHdrModel;

/**
 * Entity bean with JPA annotations Hibernate provides JPA implementation
 */
@Entity
@Table(name = "RMA_HDR")
public class RMA_HDR {

	@Id
	@Column(name = "id")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@Column(name = "rma_num")
	private String rmaNum;
	
	@Column(name = "rma_hdr_sts_cd")
	private String rmaHdrStsCd;

	@Column(name = "rtrn_tp_cd")
	private String rtrnTpCd;

	@Column(name = "rtrn_rsn_cd")
	private String rtrnRsnCd;

	@Column(name = "sell_to_cust_cd")
	private String sellToCustCd;

	@OneToMany(mappedBy = "rmaHdr", targetEntity = RMA_LINE.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
	private List<RMA_LINE> rmaLines;
	
	public RMA_HDR(){}

	public RMA_HDR(RmaHdrModel hdr) {
		this.id = hdr.getId();
		this.rmaNum = hdr.getRmaNum();
		this.rmaHdrStsCd = hdr.getRmaHdrStsCd();
		this.rtrnTpCd = hdr.getRtrnTpCd();
		this.rtrnRsnCd = hdr.getRtrnRsnCd();
		this.sellToCustCd = hdr.getSellToCustCd();
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getRmaNum() {
		return rmaNum;
	}

	public void setRmaNum(String rmaNum) {
		this.rmaNum = rmaNum;
	}

	public String getRmaHdrStsCd() {
		return rmaHdrStsCd;
	}

	public void setRmaHdrStsCd(String rmaHdrStsCd) {
		this.rmaHdrStsCd = rmaHdrStsCd;
	}

	public String getRtrnTpCd() {
		return rtrnTpCd;
	}

	public void setRtrnTpCd(String rtrnTpCd) {
		this.rtrnTpCd = rtrnTpCd;
	}

	public String getRtrnRsnCd() {
		return rtrnRsnCd;
	}

	public void setRtrnRsnCd(String rtrnRsnCd) {
		this.rtrnRsnCd = rtrnRsnCd;
	}

	public String getSellToCustCd() {
		return sellToCustCd;
	}

	public void setSellToCustCd(String sellToCustCd) {
		this.sellToCustCd = sellToCustCd;
	}

	public List<RMA_LINE> getRmaLines() {
		return rmaLines;
	}

	public void setRmaLines(List<RMA_LINE> rmaLines) {
		this.rmaLines = rmaLines;
	}
	
	public String toString() {
		return "ID:" + this.id + ", RMA_NUM:" + this.rmaNum + ", Status:" + this.rmaHdrStsCd + ", Type:" + this.rtrnTpCd + ", Reason:" + this.rtrnRsnCd;
	}
}
@Id
private RmaLinePk rmaLinePk;

Above:In “many side”, it uses the primary key field

package com.ns.spring.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * Entity bean with JPA annotations Hibernate provides JPA implementation
 */
@Entity
@Table(name = "RMA_LINE")
public class RMA_LINE {

	@Id
	private RmaLinePk rmaLinePk;

	@Column(name = "rma_line_sts_cd")
	private String rmaLineStsCd;

	@Column(name = "mdse_cd")
	private String mdseCd;

	@Column(name = "qty")
	private int qty;

	@ManyToOne
	@JoinColumn(name = "rma_id")
	private RMA_HDR rmaHdr;
	
	public RMA_LINE(){}

	public RmaLinePk getRmaLinePk() {
		return rmaLinePk;
	}

	public void setRmaLinePk(RmaLinePk rmaLinePk) {
		this.rmaLinePk = rmaLinePk;
	}

	public String getRmaLineStsCd() {
		return rmaLineStsCd;
	}

	public void setRmaLineStsCd(String rmaLineStsCd) {
		this.rmaLineStsCd = rmaLineStsCd;
	}

	public String getMdseCd() {
		return mdseCd;
	}

	public void setMdseCd(String mdseCd) {
		this.mdseCd = mdseCd;
	}

	public RMA_HDR getRmaHdr() {
		return rmaHdr;
	}

	public int getQty() {
		return qty;
	}

	public void setQty(int qty) {
		this.qty = qty;
	}

	public void setRmaHdr(RMA_HDR rmaHdr) {
		this.rmaHdr = rmaHdr;
	}

	public String toString() {
		return "PK:" + this.rmaLinePk.toString() + ", Line Status:" + this.rmaLineStsCd + ", Mdse:" + this.mdseCd + ", Qty:" + this.qty;
	}
}
private String rma_num;
private String rma_line_num;

The real primary keys which are composite defines in the following class: RmaLinePk.java

package com.ns.spring.model;

import java.io.Serializable;

import javax.persistence.Embeddable;

@Embeddable
public class RmaLinePk implements Serializable {

	private static final long serialVersionUID = -403250971215465050L;

	private String rma_num;

	private String rma_line_num;

	public RmaLinePk() {
	}

	public RmaLinePk(String rma_num, String rma_line_num) {
		this.rma_num = rma_num;
		this.rma_line_num = rma_line_num;
	}

	public String getRma_num() {
		return rma_num;
	}

	public void setRma_num(String rma_num) {
		this.rma_num = rma_num;
	}

	public String getRma_line_num() {
		return rma_line_num;
	}

	public void setRma_line_num(String rma_line_num) {
		this.rma_line_num = rma_line_num;
	}

	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		RmaLinePk other = (RmaLinePk) obj;
		if (rma_num == null) {
			if (other.rma_num != null) {
				return false;
			}
		} else if (!rma_num.equals(other.rma_num)) {
			return false;
		}
		if (rma_line_num == null) {
			if (other.rma_line_num != null) {
				return false;
			}
		} else if (!rma_line_num.equals(other.rma_line_num)) {
			return false;
		}
		return true;
	}

	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((rma_num == null) ? 0 : rma_num.hashCode());
		result = prime * result	+ ((rma_line_num == null) ? 0 : rma_line_num.hashCode());
		return result;
	}

	public String toString() {
		return "RmaLinePk:RMA#:" + this.rma_num + ", Line#:" + this.rma_line_num;
	}
}

This is how the data is stored in controller: See also Submitting a collection.

public ModelAndView submitLine(@ModelAttribute("rmaLineListModel") RmaLineListModel rmaLineListModel, Model model, HttpServletRequest req) {

	String rmaNum = rmaLineListModel.getRmaNum();
	List<RmaLineModel> currList = rmaLineListModel.getRmaLineModelList();
	if (!CommonBL.isEmpty(currList)) {
		for (RmaLineModel obj : currList) {
			String rmaLineNum = obj.getRmaLineNum();
			List<RmaLineModel> rmaLinsList = RmaDtlBL.getRmaLineListWithCdTblNm(rmaNum, rmaLineNum);
			if (CommonBL.isEmpty(rmaLinsList)) {
				// New Record
				this.rmaLineSvc.save(RmaDtlBL.getRmaLineObj(obj, rmaNum, rmaLineNum));
			}
		}
	}
	List<RmaLineModel> rmaLineModelList = RmaDtlBL.getRmaLineListWithCdTblNm(rmaNum, null);
	return getMVSubLine01(rmaNum, rmaLineModelList, req);
}

This method passes the object to be inserted/updated

public static RMA_LINE getRmaLineObj(RmaLineModel obj, String rmaNum, String rmaLineNum) {
	RMA_LINE rmaLine = new RMA_LINE();
	rmaLine.setRmaLinePk(new RmaLinePk(rmaNum, rmaLineNum));
	rmaLine.setRmaHdr(RmaBL.getRmaHdrObj(rmaNum));
	rmaLine.setRmaLineStsCd(getStsCd(obj.getRmaLineStsCd()));
	rmaLine.setMdseCd(obj.getMdseCd());
	rmaLine.setQty(obj.getQty());
	return rmaLine;
}

Static Factory Pattern

design-pattern-hdr_img2
It is always good to use Design Pattern in your application, although it is not required, in order to avoid spaghetti. One of popular design pattern is Factory pattern. The concept is similar to DI (Dependency Injection). In this example, I use Static Factory pattern.
stat-facto-pattern-diagram1
With Factory pattern, you can instantiate a class with “new” (Source Code)

@RequestMapping("/cUrlValSubLine01Jsp/{rmaNum}")
public ModelAndView goToSubLine01Jsp(@PathVariable("rmaNum") String rmaNum,	Model model, HttpServletRequest req) {
	List<RmaLineModel> rmaLineModelList = RmaDtlBL.getRmaLineListWithCdTblNm(rmaNum, null);
	return getMVSubLine01(rmaNum, rmaLineModelList, req);
}

This method is being called to set ModelAndView object, and one of them is the list of code for auto-complete feature

private ModelAndView getMVSubLine01(String rmaNum, List<RmaLineModel> rmaLinsList, HttpServletRequest req) {

	RmaLineListModel newModel = new RmaLineListModel(rmaNum, rmaLinsList);

	ModelAndView modelAndView = new ModelAndView(VIEW.SUB_LINE_01.getVal());
	modelAndView.addObject(CONST.FORM_KEY.getVal(), newModel);
	// For item detail list
	modelAndView.addObject(CONST.LINE_LIST_MODEL.getVal(), newModel);
	// Setup Status drop down line the item list
	modelAndView.addObject(CONST.HDR_STS_LIST.getVal(), getList(CONST.HDR_STS_LIST.getVal()));
	// Item list for AJAX Auto complete
	req.getSession().setAttribute(CONST.MDSE_LIST.getVal(), getList(CONST.MDSE_LIST.getVal()));
	return modelAndView;
}

Above line 12 calls this method:

private List<?> getList(String key) {
	BLFactory fact = BLFactory.getInstance(key);
	return fact.getList();
}

Above line 12 calls this method:

package com.ns.spring.common.gen;

import java.util.List;

import com.ns.spring.constant.RtrnConstant;

public class BLFactory implements RtrnConstant {

	private BLService svc;

	private BLFactory(String param) {
		if (CONST.HDR_STS_LIST.getVal().equals(param)) {
			this.svc = new RtrnCommonBL();
		} else if (CONST.TP_LIST.getVal().equals(param)) {
			this.svc = new TpCommonBL();
		} else if (CONST.MDSE_LIST.getVal().equals(param)) {
			this.svc = new MdseCommonBL();
		}
	}

	// static factory
	public static BLFactory getInstance(String param) {
		return new BLFactory(param);
	}

	public List<?> getList() {
		return this.svc.getList();
	}
}

This factory class returns static instance via interface BLService.

package com.ns.spring.common.gen;

import java.util.List;

public interface BLService {
	public List<?> getList();
}
package com.ns.spring.common.gen;

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.common.CommonBL;
import com.ns.spring.constant.RtrnConstant.CONST;
import com.ns.spring.model.MDSE;
import com.ns.spring.model.RMA_HDR_STS;
import com.ns.spring.model.RTRN_TP;
import com.ns.spring.model.ui.MdseModel;
import com.ns.spring.model.ui.RmaHdrStsModel;
import com.ns.spring.model.ui.RtrnTpModel;
import com.ns.spring.service.template.MdseService;
import com.ns.spring.service.template.RmaHdrStsService;
import com.ns.spring.service.template.RtrnTpService;

@Component
public class MdseCommonBL implements BLService {

	private static MdseService mdseSvc;
	
	@Autowired(required = true)
	public void setMdseSvc(MdseService mdseSvc) {
		this.mdseSvc = mdseSvc;
	}

	@Override
	public List<MdseModel> getList() {
		List<MdseModel> mdseModelList = new ArrayList<>();
		List<MDSE> mdseList = mdseSvc.findAll();
		if (!CommonBL.isEmpty(mdseList)) {
			for (int i = 0; i < mdseList.size(); i++) {
				MDSE obj = (MDSE) mdseList.get(i);
				mdseModelList.add(new MdseModel(i, obj.getMdseCd()));
			}
		}
		return mdseModelList;
	}
}

getList() eventually calls findAll() that returns all record from MDSE table.

Generic DAO with Custom Method

db-chain1
Instead of having DAO for each entity, calling Generic DAO simplify the program.
Unlike the template classes with empty method that can only use the method specified in Generic DAO classes, this example use additional customized method (Source Code)

2015-05-30_11h15_25

2015-05-30_11h17_10

package com.ns.spring.dao.template;

import java.util.List;

import com.ns.spring.dao.GenHbDao;
import com.ns.spring.model.RMA_LINE;

public interface RmaLineDao extends GenHbDao<RMA_LINE, String> {

	public List<Object[]> getListRmaLineBySql(String rmaNum, String rmaLineNum);
	public RMA_LINE getRmaLineByHql(String rmaNum, String rmaLineNum);
}
package com.ns.spring.dao.template.impl;
package com.ns.spring.dao.template.impl;

import java.util.List;

import org.hibernate.Query;
import org.springframework.stereotype.Repository;

import com.ns.spring.dao.GenHbDaoImpl;
import com.ns.spring.dao.template.RmaLineDao;
import com.ns.spring.model.RMA_LINE;

@Repository
public class RmaLineDaoImpl extends GenHbDaoImpl<RMA_LINE, String> implements RmaLineDao {

	@SuppressWarnings("unchecked")
	@Override
	public List<Object[]> getListRmaLineBySql(String rmaNum, String rmaLineNum) {
		
		StringBuilder sb = new StringBuilder();
		sb.append("\n");
		sb.append("SELECT\n");
		sb.append("  rl.rma_num\n");
		sb.append(" ,rl.rma_line_num\n");
		sb.append(" ,rl.rma_line_sts_cd\n");
		sb.append(" ,sts.rma_hdr_sts_nm\n");
		sb.append(" ,rl.mdse_cd\n");
		sb.append(" ,mdse.mdse_nm\n");
		sb.append(" ,rl.qty\n");
		sb.append(" ,rl.rma_id\n");
		sb.append("FROM RMA_LINE rl\n");
		sb.append("LEFT OUTER JOIN RMA_HDR_STS sts\n");
		sb.append("ON rl.rma_line_sts_cd = sts.rma_hdr_sts_cd\n");
		sb.append("LEFT OUTER JOIN MDSE mdse\n");
		sb.append("ON rl.mdse_cd = mdse.mdse_cd\n");
		sb.append("WHERE rl.rma_num = :rmaNum\n");
		if (rmaLineNum != null) {
			sb.append("AND rl.rma_line_num = :rmaLineNum\n");
		}		
		sb.append("ORDER BY\n");
		sb.append("  rl.rma_num\n");
		sb.append(" ,rl.rma_line_num\n");

		Query query = super.getCurrSession().createSQLQuery(sb.toString());
		query.setParameter("rmaNum", rmaNum);
		if (rmaLineNum != null) {
			query.setParameter("rmaLineNum", rmaLineNum);
		}
		List<Object[]> list = query.list();
		return list;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public RMA_LINE getRmaLineByHql(String rmaNum, String rmaLineNum) {

		String hqlStr = "from RMA_LINE " 
				+ "where rma_num = :rmaNum "
				+ "and   rma_line_num = :rmaLineNum ";
		
		Query query = super.getCurrSession().createQuery(hqlStr);
		query.setParameter("rmaNum", rmaNum);
		query.setParameter("rmaLineNum", rmaLineNum);

		List<RMA_LINE> list = query.list();
		if (list != null && list.size() > 0) {
			return (RMA_LINE) list.get(0);
		}
		return null;
	}
}

DAO interface, and it’s implementation has two additional methods:
1. Native SQL with its reesult
2. HQL with its reesult

package com.ns.spring.service.template;

import java.util.List;

import com.ns.spring.model.RMA_LINE;
import com.ns.spring.service.GenHbService;

public interface RmaLineService extends GenHbService<RMA_LINE, String> {

	public List<Object[]> getListRmaLineBySql(String rmaNum, String rmaLineNum);
	public RMA_LINE getRmaLineByHql(String rmaNum, String rmaLineNum);
}
package com.ns.spring.service.template.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ns.spring.dao.GenHbDao;
import com.ns.spring.dao.template.RmaLineDao;
import com.ns.spring.model.RMA_LINE;
import com.ns.spring.service.GenHbServiceImpl;
import com.ns.spring.service.template.RmaLineService;

@Service("rmaLineService")
public class RmaLineServiceImpl extends GenHbServiceImpl<RMA_LINE, String> implements RmaLineService {

	private RmaLineDao dao;

	public RmaLineServiceImpl() {
	}

	@Autowired
	public RmaLineServiceImpl(@Qualifier("rmaLineDaoImpl") GenHbDao<RMA_LINE, String> genericDao) {
		super(genericDao);
		this.dao = (RmaLineDao) genericDao;
	}
	
	@Override
	@Transactional
	public List<Object[]> getListRmaLineBySql(String rmaNum, String rmaLineNum) {
		return this.dao.getListRmaLineBySql(rmaNum, rmaLineNum);
	}

	@Override
	@Transactional
	public RMA_LINE getRmaLineByHql(String rmaNum, String rmaLineNum) {
		return this.dao.getRmaLineByHql(rmaNum, rmaLineNum);
	}
}

DAO service interface, and it’s implementation calling super class, and two custom method defined in RmaLineDaoImpl.

Generic DAO without Custom Method

db-chain1
Instead of having DAO for each entity, calling Generic DAO simplify the program. (Source Code)

2015-05-30_09h48_00

2015-05-30_09h53_38

package com.ns.spring.dao.template;

import com.ns.spring.dao.GenHbDao;
import com.ns.spring.model.MDSE;

public interface MdseDao extends GenHbDao<MDSE, String> {

}
package com.ns.spring.dao.template.impl;

import org.springframework.stereotype.Repository;

import com.ns.spring.dao.GenHbDaoImpl;
import com.ns.spring.dao.template.MdseDao;
import com.ns.spring.model.MDSE;

@Repository
public class MdseDaoImpl extends GenHbDaoImpl<MDSE, String> implements MdseDao {

}

Empty DAO interface, and it’s implementation

package com.ns.spring.service.template;

import com.ns.spring.model.MDSE;
import com.ns.spring.service.GenHbService;

public interface MdseService extends GenHbService<MDSE, String> {

}

package com.ns.spring.service.template.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.ns.spring.dao.GenHbDao;
import com.ns.spring.dao.template.MdseDao;
import com.ns.spring.model.MDSE;
import com.ns.spring.service.GenHbServiceImpl;
import com.ns.spring.service.template.MdseService;

@Service("mdseService")
public class MdseServiceImpl extends GenHbServiceImpl<MDSE, String> implements MdseService {

	private MdseDao dao;

	public MdseServiceImpl() {
	}

	@Autowired
	public MdseServiceImpl(@Qualifier("mdseDaoImpl") GenHbDao<MDSE, String> genericDao) {
		super(genericDao);
		this.dao = (MdseDao) genericDao;
	}
}

Empty DAO service interface, and it’s implementation calling super class. It can use the method defined in Generic DAO

Auto Complete

autocomplete3
In Biz web apps, an end user often need to enter some code that he/she cannot memorize. For for example, a product code. And auto complete is very helpful and it is a commonly used in Ajax.

Summarized as two steps

  1. Javascript function is being called every time a key stroked on keyboard
  2. Ajax calls a controller class and the controller class returns a suggested list

2015-05-29_07h14_55


1. Javascript function is being called every time a key stroked on keyboard

<form:input path="mdseCd" id="idItemCd" style="height:25px; width:200px" />

Step 1.1. Javascript (Ajax) will be called as user types a key

$('#idItemCd').autocomplete({
   serviceUrl: '${pageContext.request.contextPath}/autoCompleteList',
   paramName: "inputVal",
   delimiter: ",",
   transformResult: function(response) {
       return {
           suggestions: $.map($.parseJSON(response), function(item) {
               return {
                   value: item.mdseCd,
                   data: item.id
               };
           })
       };
   }
});

Step 1.2. This Ajax send a request to the controller method:


2. Ajax calls a controller class and the controller class returns a suggested list

@RequestMapping(value = "/autoCompleteList", method = RequestMethod.GET)
public @ResponseBody List<MdseModel> getTags(@RequestParam(value = "inputVal") String inputVal, HttpServletRequest req) {
	List<MdseModel> entireSessionList = (List<MdseModel>)req.getSession().getAttribute(CONST.MDSE_LIST.getVal());
	List<MdseModel> resultList = new ArrayList<MdseModel>();
	if (!CommonBL.isEmpty(entireSessionList)) {
		for (MdseModel obj : entireSessionList) {
			// Fuzzy search
			if (obj.getMdseCd().contains(inputVal)) {
				resultList.add(obj);
			}
		}
	}
	return resultList;
}

Step 2.1. At line 3, getting a entireSessionList contains an entire list that has been created as the screen is initialized.
2015-05-30_08h10_19
Step 2.2. At line 8 to 10, the method creating a list that starts from “5508
Step 2.3. At line 13, the method returns the list as JSON object.

Multiple Row Form Submit

submit-multi-form2
In biz apps, it is a common requirement that the data stays in the screen but not in the data base. And it’s pretty painful, compared to insert the record every time the user add it.

Suppose your screen displaying a list, and you have added more than one rows at once (But not in the Database yet)
submit-multiple-rows1
Once submitted, the added rows are in the Database:
submit-multiple-rows2

Summarized as two steps:

  1. The each row added one by one in the screen
  2. All rows are inserted/updated to the Database

@RequestMapping(value = "/cUrlValAttrbSubLine01Jsp", params = "addItemSubLine01", method = RequestMethod.POST)
public ModelAndView addItemSubLine01(@ModelAttribute("rmaLineListModel") RmaLineListModel rmaLineListModel, Model model, HttpServletRequest req) {
	
	ModelAndView modelAndView = new ModelAndView(VIEW.SUB_LINE_01.getVal());
	modelAndView.addObject(CONST.FORM_KEY.getVal(), rmaLineListModel);

	String rmaNum = rmaLineListModel.getRmaNum();
	String mdseCd = rmaLineListModel.getMdseCd();
	String mdseNm = CommonBL.getMdseNm(CommonBL.getMdse(mdseCd));
	List<RmaLineModel> currList = rmaLineListModel.getRmaLineModelList();
	
	RmaLineModel newRow = new RmaLineModel();
	newRow.setRmaNum(rmaNum);
	newRow.setRmaLineNum(RmaDtlBL.getNewLineNum(currList));
	newRow.setMdseCd(mdseCd);
	newRow.setMdseNm(mdseNm);
	currList.add(newRow);
	
	rmaLineListModel.setRmaLineModelList(currList);		
	modelAndView.addObject(CONST.LINE_LIST_MODEL.getVal(), rmaLineListModel);
	modelAndView.addObject(CONST.HDR_STS_LIST.getVal(), CommonBL.getStsList(req));	
	return modelAndView;
}

At Step 1, in the Controller method, line between 12 to 17, adding a new Object added to the list

@RequestMapping(value = "/cUrlValAttrbSubLine01Jsp", params = "submitLine", method = RequestMethod.POST)
public ModelAndView submitLine(@ModelAttribute("rmaLineListModel") RmaLineListModel rmaLineListModel, Model model, HttpServletRequest req) {

	String rmaNum = rmaLineListModel.getRmaNum();
	List<RmaLineModel> currList = rmaLineListModel.getRmaLineModelList();
	if (!CommonBL.isEmpty(currList)) {
		for (RmaLineModel obj : currList) {
			String rmaLineNum = obj.getRmaLineNum();
			List<RmaLineModel> rmaLinsList = RmaDtlBL.getRmaLineListWithCdTblNm(rmaNum, rmaLineNum);
			if (CommonBL.isEmpty(rmaLinsList)) {
				// New Record
				this.rmaLineSvc.save(RmaDtlBL.getRmaLineObj(obj, rmaNum, rmaLineNum));
			}
		}
	}
	List<RmaLineModel> rmaLineModelList = RmaDtlBL.getRmaLineListWithCdTblNm(rmaNum, null);
	return getMVSubLine01(rmaNum, rmaLineModelList, req);
}

At Step 2, in the Controller, it takes a parameter (Model class) contains a list, and the three added rows are now added.

HTML Table Creation

hdr-ajax-tempate3
More biz web apps are using Javascript because of its capability; Handling an event.
In this example, the HTML tables are constructed on changing event of select box.

Summary

  • The table on left side constructed by a result of SQL (as select box value has been changed)
  • The table on right side constructed by a result of different SQL (at the same time of when the one in the left constructed)

dinamic-table-creation-result2
compare-two-tables1

Summarized as Four steps

  1. Select box has changed and the Javascript (Ajax) send request to the Controller
  2. The Controller method create a object for two tables (LEFT and RIGHT) and send back response
  3. Javascript (Ajax) receives a response and construct two set of HTML
  4. Two HTML tables (LEFT and RIGHT) are created by jQuery

1. Select box has changed and the Javascript (Ajax) send request to the Controller

<form:select path="rtrnTpCd" id="tpCd" onchange="onChangeTp();" style="height:25px; width:200px">
   <form:option value="" label="--- Select Type ---"/>
   <c:forEach items="${TP_LIST}" var="name">
      <c:choose>
         <c:when test="${name.getRtrnTpCd()== TP_SELECTED}">
            <form:option value="${name.getRtrnTpCd()}" selected="true">${name.getRtrnTpNm()}</form:option>
         </c:when>
         <c:otherwise>
            <form:option value="${name.getRtrnTpCd()}">${name.getRtrnTpNm()}</form:option>
         </c:otherwise>
      </c:choose>
   </c:forEach>
</form:select>

Step 1.1. At line 1, when select box is selected, it’s calling Javascript function “onChangeTp()“.

function onChangeTp() {
   var selectedTpCd = $('#tpCd').val();
   $.ajax({
      type : "Get", 
      url : "onChangeTpCdTpRsn01",
      data : "tpCd=" + selectedTpCd,
      success : function(response) {
         // Remove the row excluding the first row
         $("#idTableRsnBound").find("tr:gt(0)").remove();
         $("#idTableRsnUnBound").find("tr:gt(0)").remove();
         var trHtmlBound = '';
         var trHtmlUnBound = '';
         $.each(response, function(k, v) {
            var thisTpCd = v.rtrnTpCd;
            if(thisTpCd == selectedTpCd) {
               trHtmlBound = getRsnLines(trHtmlBound, k, v);
            } else {
               trHtmlUnBound = getRsnLines(trHtmlUnBound, k, v);
            }
         });
         $('#idTableRsnBound').append(trHtmlBound);
         $('#idTableRsnUnBound').append(trHtmlUnBound);
      },
      error : function(e) {
         alert('Error onChangeTp: ' + e);
      }
   });
}

Step 1.2. At line 5, the Ajax request for the controller “onChangeTpCdTpRsn01“.


2. The Controller method create a object for two tables (LEFT and RIGHT) and send back response

@RequestMapping(value = "/onChangeTpCdTpRsn01")
public @ResponseBody List<RtrnRsnModel> refreshTypeComb(@RequestParam(value = "tpCd") String rtrnTpCd, Model model, HttpServletRequest req) {

	model.addAttribute(CONST.FORM_KEY.getVal(), new RtrnTpModel());
	model.addAttribute("rtrnTpCd", rtrnTpCd);
	model.addAttribute(CONST.TP_SELECTED.getVal(), rtrnTpCd);
	req.getSession().setAttribute(CONST.TP_SELECTED.getVal(), rtrnTpCd);
	initBoundUnboundRsnList(rtrnTpCd, req);

	List<RtrnRsnModel> rsnBoundList = (List<RtrnRsnModel>)req.getSession().getAttribute(CONST.RSN_LIST_BOUND.getVal());
	List<RtrnRsnModel> rsnUnBoundList = (List<RtrnRsnModel>)req.getSession().getAttribute(CONST.RSN_LIST_UNBOUND.getVal());
	List<RtrnRsnModel> rsnList = new ArrayList<RtrnRsnModel>();
	TpRsnBL.setNewRsnList(rsnList, rsnBoundList);
	TpRsnBL.setNewRsnList(rsnList, rsnUnBoundList);
	return rsnList;
}

Step 2.1. At line 10, set the SQL result for the LEFT SIDE table.
Step 2.2. At line 11, set the SQL result for the RIGHT SIDE table.

[
	Reason Code:001, Name:Item Damaged, Type:01,
	Reason Code:002, Name:Did not order, Type:01,
	Reason Code:003, Name:Customer has moved, Type:01,
	Reason Code:004, Name:Cancelled by customer, Type:01,
	Reason Code:007, Name:Customer did not like it, Type:01,
	Reason Code:005, Name:Customer being bunkrupt, Type:,
	Reason Code:006, Name:Defective Item, Type:,
	Reason Code:008, Name:Duplicated order, Type:,
	Reason Code:009, Name:Change his/her mind, Type:,
	Reason Code:010, Name:Item lost, Type:,
	Reason Code:011, Name:Wrong address, Type:,
	Reason Code:012, Name:Wrong Item, Type:
]

Step 2.3. At line 15, return as one object (ABOVE) combined LEFT and RIGHT tables.

NOTE: Line 2 to 6 ends with “Type:01” will be the LEFT table


3. Javascript (Ajax) receives a response and construct two tables

function onChangeTp() {
   var selectedTpCd = $('#tpCd').val();
   $.ajax({
      type : "Get", 
      url : "onChangeTpCdTpRsn01",
      data : "tpCd=" + selectedTpCd,
      success : function(response) {
         // Remove the row excluding the first row
         $("#idTableRsnBound").find("tr:gt(0)").remove();
         $("#idTableRsnUnBound").find("tr:gt(0)").remove();
         var trHtmlBound = '';
         var trHtmlUnBound = '';
         $.each(response, function(k, v) {
            var thisTpCd = v.rtrnTpCd;
            if(thisTpCd == selectedTpCd) {
               trHtmlBound = getRsnLines(trHtmlBound, k, v);
            } else {
               trHtmlUnBound = getRsnLines(trHtmlUnBound, k, v);
            }
         });
         $('#idTableRsnBound').append(trHtmlBound);
         $('#idTableRsnUnBound').append(trHtmlUnBound);
      },
      error : function(e) {
         alert('Error onChangeTp: ' + e);
      }
   });
}

Step 3.1. At line 7, get the response from the controller (one list as JSON object)
Step 3.2. At line 9 and 10, clear the LEFT and RIGHT to be re-constructed

function getRsnLines(trHtml, idx, dataObj) {
   //Get each key and value from the list
   var code = dataObj.rtrnRsnCd;
   var val = dataObj.rtrnRsnNm;
   trHtml +=
	      '<tr>'
	      + '<td>'
	      +   '<input id="selectedCheckBox'+idx+'" name="selectedCheckBox" type="checkbox" value="'+code+'"/>'
	      + '</td>'
	      + '<td>'+code+'</td>'
	      + '<td>'+val+'</td>'
	      +'</tr>';
   return trHtml;
}

Step 3.3. At line 15 to 19, create two HTML tables (LEFT and RIGHT) by function “getRsnLines” (above).


4. Two HTML tables (LEFT and RIGHT) are created by jQuery

function onChangeTp() {
   var selectedTpCd = $('#tpCd').val();
   $.ajax({
      type : "Get", 
      url : "onChangeTpCdTpRsn01",
      data : "tpCd=" + selectedTpCd,
      success : function(response) {
         // Remove the row excluding the first row
         $("#idTableRsnBound").find("tr:gt(0)").remove();
         $("#idTableRsnUnBound").find("tr:gt(0)").remove();
         var trHtmlBound = '';
         var trHtmlUnBound = '';
         $.each(response, function(k, v) {
            var thisTpCd = v.rtrnTpCd;
            if(thisTpCd == selectedTpCd) {
               trHtmlBound = getRsnLines(trHtmlBound, k, v);
            } else {
               trHtmlUnBound = getRsnLines(trHtmlUnBound, k, v);
            }
         });
         $('#idTableRsnBound').append(trHtmlBound);
         $('#idTableRsnUnBound').append(trHtmlUnBound);
      },
      error : function(e) {
         alert('Error onChangeTp: ' + e);
      }
   });
}

At line 21 and 22, two set of HTML will be set to the ID specified:

<div class="id_Bound">
<table id="idTableRsnBound" class="tg" border="1">
	<tr>
		<th width="20"></th>
		<th width="80">Reason Code</th>
		<th width="120">Reason Name</th>
	</tr>							
	<c:forEach items="${RSN_LIST_BOUND}" var="rsnVal" varStatus="loop">
		<tr>
			<td><form:checkbox path="selectedCheckBox" value="${rsnVal.rtrnRsnCd}"/></td>
			<td>${rsnVal.rtrnRsnCd}</td>
			<td>${rsnVal.rtrnRsnNm}</td>
		</tr>
	</c:forEach>
</table>
</div>

Step 4.1. At line 21, create (set HTML) to the table on the LEFT (#idTableRsnBound)

<div class="id_UnBound">
<table id="idTableRsnUnBound" class="tg" border="1">
	<tr>
		<th width="20"></th>
		<th width="80">Reason Code</th>
		<th width="120">Reason Name</th>
	</tr>
	<c:forEach items="${RSN_LIST_UNBOUND}" var="rsnVal" varStatus="loop">
		<tr>
			<td><form:checkbox path="selectedCheckBox" value="${rsnVal.rtrnRsnCd}"/></td>
			<td>${rsnVal.rtrnRsnCd}</td>
			<td>${rsnVal.rtrnRsnNm}</td>
		</tr>
	</c:forEach>
</table>
</div>

Step 4.2. At line 22, create (set HTML) to the table on the RIGHT (#idTableRsnUnBound)

Submitting a Form

submit-form-img1
Unlike updating a part of screen by Ajax, this is a traditional(?), and a basic way: to Submit an entire form.

Summarized as three steps:

  1. SUBMIT button is pressed, and passes an Forms (Object) to the controller method.
  2. The Controller method takes the Object and Register (Insert/Update) to the data base
  3. Return a String as JSP name

The Detail of Step 1
submit-form-take-param1

@RequestMapping(value = "/cUrlValAttrbMain01Jsp", params = "submitHdr", method = RequestMethod.POST)
public String submitHdr(@ModelAttribute("RmaHdrModel") RmaHdrModel rma, HttpServletRequest req) {
	RmaBL.saveHdr(rma, req);
	return VIEW.REDIRECT_HOME.getVal();
}

1.1.cUrlValAttrbMain01Jsp” is defined in main_01.jsp.

<c:url var="addAction" value="/cUrlValAttrbMain01Jsp.html" ></c:url>
<form:form action="${addAction}" commandName="rmaMapKey">

1.2.submitHdr” is “name” attribute in “Submit” button in main_01.jsp.

<input type="submit" value="Submit" name="submitHdr" style="height:25px; width:150px; color: #F6FDA4; background-color: #CC0000; font-face: 'Comic Sans MS';"/>

1.3. @ModelAttribute specifies an argument in the Controller class RmaController.java.
1.4. The parameter “RmaHdrModel rma” takes the form object from JSP.


The Detail of Step 2 & 3
submit-form-step-2-3

@RequestMapping(value = "/cUrlValAttrbMain01Jsp", params = "submitHdr", method = RequestMethod.POST)
public String submitHdr(@ModelAttribute("RmaHdrModel") RmaHdrModel rma, HttpServletRequest req) {
	RmaBL.saveHdr(rma, req);
	return VIEW.REDIRECT_HOME.getVal();
}

2.1. RmaBL.saveHdr does insert/update to the Database

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;
}

3.1.VIEW.REDIRECT_HOME.getVal()” returns a string “redirect:/ns-home” from a constant class and redirect to the method initialize the screen

enum VIEW {
	
	MAIN_01("main_01"),
	SUB_LINE_01("sub_line_01"),
	SUB_TP_01("sub_tp_01"),
	SUB_RSN_01("sub_rsn_01"),
	SUB_TP_RSN_01("sub_tp_rsn_01"),
	REDIRECT_HOME("redirect:/ns-home")
	;
	
	private String code;

	VIEW(String code) {
		this.code = code;
	}

	public String getVal() {
		return code;
	}
}

Updating an MVC Partial View

hdr-ajax-partial-update-img1
Unlike submitting a ENTIRE FORM, Ajax web apps is commonly used to update ONLY A PART OF HTML. This section is continued from the previous section.
partial-mvc-update
This example only update one of multiple rows in a HTML:

radio-button-selected-and-copied-img1
(Above image) Copied fields (on the right side) will be registered in Data base and the row in a screen. (Below image)
updated-row1

Summarized as five steps:

  1. Take the form values from the form and call the Javascript (with Ajax) function
  2. Send request to the Controller with the object
  3. The controller receives the request and register the database
  4. The controller response the Ajax with the object
  5. J-Query function update the HTML as response object

2015-05-25_21h12_31
By Pressing this button:

<input type="button" id="idSubmitHdr" value="Update RMA" style="height:25px; width:150px; color: #F6FDA4; background-color: #0400FF; font-face: 'Comic Sans MS';"/>
$(function() {
   $('#idSubmitHdr').on('click',function() {

      var idId = $("#idId").val();
      var idRmaNum = $("#idRmaNum").val();
      var id_tpCd = $("div.id_tpCd select").val();
      var id_RsnCd = $("div.id_RsnCd select").val();
      var idSellTo = $("#idSellTo").val();
      var id_HdrSts = $("div.id_HdrSts select").val();

      var rmaHdrModel = {
         "id" : idId,
         "rmaNum" : idRmaNum,
         "rtrnTpCd" : id_tpCd,
         "rtrnRsnCd" : id_RsnCd,
         "sellToCustCd" : idSellTo,
         "rmaHdrStsCd" :id_HdrSts
      }
      $.ajax({
         type : 'POST', 
         url : 'submitHdrByJsonMain01',
         contentType : 'application/json; charset=utf-8',
         dataType : 'json',
         data: JSON.stringify(rmaHdrModel),
         success : function(data) {
            modifyRowData(data);
         },
         error : function(e) {
            alert("error:" +response+ ":" +e);
         }
      });
   });
});

Step 1. The above Javascript function takes six values from the form, and created as one object (Line 2 and 12 to 17).
Step 2. Send request to the Controller with the object
NOTE: use “JSON.stringify” function (line 24)

@RequestMapping(value = "/submitHdrByJsonMain01", method = RequestMethod.POST)
public @ResponseBody RmaHdrModel submitHdrByJson(@RequestBody RmaHdrModel rma, HttpServletRequest req) {		
	RMA_HDR obj = RmaBL.saveHdr(rma, req);
	return RmaBL.getRmaHdrModel(obj.getRmaNum());
}

Step 3 and 4. The controller receives the request and register the data base and returns a JSON object to Javascript.

function modifyRowData(newData) {
   var id = newData.id;
   var rmaNum = newData.rmaNum;
   var stsCd = newData.rmaHdrStsCd;
   var stsNm = newData.rmaHdrStsNm;
   var tpCd = newData.rtrnTpCd;
   var tpNm = newData.rtrnTpNm;
   var rsnCd = newData.rtrnRsnCd;
   var rsnNm = newData.rtrnRsnNm;
   var custCd = newData.sellToCustCd;

   $('#IdHdrDtl tr').each(function() { 
      var currRmaNum = $(this).find('td').eq(3).text(); // rmaNum
      var currStsCd = $(this).find('td').eq(4).text(); // StsCd
      var currStsNm = $(this).find('td').eq(5).text();
      var currTpCd = $(this).find('td').eq(6).text(); // TpCd
      var currTpNm = $(this).find('td').eq(7).text();
      var currRsnCd = $(this).find('td').eq(8).text(); // RsnCd
      var currRsnNm = $(this).find('td').eq(9).text();
      var currCustCd = $(this).find('td').eq(10).text(); // CustCd

      var idRmaNum = $(this).find('td').eq(3).attr('id');
      var idStsCd = $(this).find('td').eq(4).attr('id');
      var idStsNm = $(this).find('td').eq(5).attr('id');
      var idTpCd = $(this).find('td').eq(6).attr('id');
      var idTpNm = $(this).find('td').eq(7).attr('id');
      var idRsnCd = $(this).find('td').eq(8).attr('id');
      var idRsnNm = $(this).find('td').eq(9).attr('id');
      var idCustCd = $(this).find('td').eq(10).attr('id');

      if(rmaNum == currRmaNum) {
         $("#"+ idStsCd).html(stsCd);
         $("#"+ idStsNm).html(stsNm);
         $("#"+ idTpCd).html(tpCd);
         $("#"+ idTpNm).html(tpNm);
         $("#"+ idRsnCd).html(rsnCd);
         $("#"+ idRsnNm).html(rsnNm);
         $("#"+ idCustCd).html(custCd);
         return false;
      }
   });
}

Step 5. Another Javascript function “modifyRowData” (Above) called and J-Query function update a part of HTML (specified row in this example).