Spring MVC using STS within Eclipse

spring-sts-header-img2
Spring MVC is widely used for java web apps. We usually use Eclipse IDE to develop them. Spring Tool Suite (STS) that is an IDE based on Eclipse and comes with its plugin. There are a lot of examples online, but they often different because they keep changing its user interface. Here is the memo

eclipse-sts-step1
File -> New -> Other… -> Spring -> Spring Legacy Project
eclipse-sts-step1
Old tutorials are usually just “Spring Project”, but now has the word “Lagacy” in it..
eclipse-sts-step2
For the first time, you will be asked..
eclipse-sts-step3
Need to entering the project path, then “Finish”.
Selection_003
Maven project hierarchy automatically created including POM.xml.

└── src
    └── main
        └── java
            └── com.ns.spring.Contoller class

Spring + Hibernate Config

hiv-mvc-img

To make your Spring MVC program work with Hibernate, Following files need to be modified:

For more info, see: Spring MVC Config

<beans:bean id="dataSource" 
        class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <beans:property name="url"      value="jdbc:mysql://localhost:3306/ns201501" />
    <beans:property name="username" value="root" />
    <beans:property name="password" value="nobu" />
</beans:bean>

This is a part of servlet-context.xml. In this case, DB is MySQL.

<!-- Hibernate 4 SessionFactory Bean definition -->
<beans:bean id="hibernate4AnnotatedSessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <beans:property name="dataSource" ref="dataSource" />
    <beans:property name="annotatedClasses">
        <beans:list>
            <beans:value>com.ns.spring.model.RMA_HDR</beans:value>
            <beans:value>com.ns.spring.model.RMA_LINE</beans:value>
            <beans:value>com.ns.spring.model.RTRN_TP</beans:value>
            <beans:value>com.ns.spring.model.RTRN_RSN</beans:value>
            <beans:value>com.ns.spring.model.RTRN_TP_RSN</beans:value>
            <beans:value>com.ns.spring.model.RTRN_TP_RSN_CMBN</beans:value>
            <beans:value>com.ns.spring.model.RMA_HDR_STS</beans:value>
            <beans:value>com.ns.spring.model.MDSE</beans:value>
            <beans:value>com.ns.spring.model.RmaLinePk</beans:value>
            <beans:value>com.ns.spring.model.RtrnTpRsnPk</beans:value>
            <beans:value>com.ns.spring.model.ui.RmaHdrModel</beans:value>
            <beans:value>com.ns.spring.model.ui.RmaHdrStsModel</beans:value>
            <beans:value>com.ns.spring.model.ui.RmaLineModel</beans:value>
            <beans:value>com.ns.spring.model.ui.RtrnRsnModel</beans:value>
            <beans:value>com.ns.spring.model.ui.RtrnTpModel</beans:value>
        </beans:list>
    </beans:property>
    <beans:property name="hibernateProperties">
        <beans:props>
            <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</beans:prop>
            <beans:prop key="hibernate.show_sql">true</beans:prop>
        </beans:props>
    </beans:property>
</beans:bean>

This part defines the classes for CRUD operation. For example, line 7 is the class for Hibernate object (below) represent the table RMA_HDR.

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();
	}
	// getter and setter
}
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
;
<!-- Hibernate -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>${hibernate.version}</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>${hibernate.version}</version>
</dependency>
<!-- Apache Commons DBCP -->
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>
<!-- MySQL -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.9</version>
</dependency>

This is a part of pom.xml. As line 18 to 23, DB is MySQL.

Overview (Dependency Injection)

di-decouple-hdr-img1
DI (Dependency Injection) is one of key features in Spring framework beside (AOP). Spring is the framework that try to decouple the program in many way.

DI is one of ways to decouple the program like a Factory Pattern. In your code, you can GET RID OFnew” statement to create an object.


Example of Dependency:
In your code, the method A need object A1 in order to run it.

Example of Dependency Injection:
Your method A doesn’t have to create a object A1, instead, the object can be injected from somewhere else.

What is good about it?
Your method A can run it without object A1 that makes easier to test it.


There are three ways to do this in Spring framework:

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

Screen Transition (With More than one Controllers)

multiple-relaiton-image-mvc2
In Spring MVC Web apps, there might be multiple combination between Controller, JSP(View), and Object class(Model). In other words, almost any combination is possible.

It is a lot more flexible compared to Struts which tied one Action class (controller class) tied with Form class (object model class).

mvc-classes-diagram-img1
There are number of Controller, Model classes, and views (JSP) in one Web App, and this examples shows the screen transition involved between two controllers and views (JSP).
screen-transition-img1 (1)
Summarized as four steps:

  1. First Controller calls the first JSP.
  2. First JSP calls the second Controller.
  3. Second Controller calls the second JSP.
  4. Second JSP is initialized.

Step 1 to 2. The first Controller (RmaController.java) calls main_01.jsp.
Step 2 to 3. The main_01.jsp calls second controller RmaDtlController.java.
Step 4. The second JSP (sub_line_01.jsp) is initialized.


Again (1 to 2), the first controller (RmaController.java) is invoked by a link, and calls second controller (RmaDtlController.java).
screen-tran-radio1
2015-06-07_22h29_16
Let’s look at step (2 to 3):
The main_01.jsp calls second controller RmaDtlController.java once the link is clicked (line 16).

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

screen-tran-link-param-img1
In the line 16:
2.1. Link clicked contains an ID (RMA000016)
2.2.cUrlValSubLine01Jsp” specified in second JSP (sub_line_01.jsp) and it will be called
url-scrn-trans-rmaline1
2.3. The URL for second JSP: http://localhost:8080/NS2015V07/cUrlValSubLine01Jsp/RMA000016


Step 3: Second Controller calls the second JSP.

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

3.1. Returns ModelAndView object

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

In the line 5:
3.2. Get the view name (“sub_line_01”) as constant (below) and set it to the object

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

Step 4: Second JSP is initialized.
2015-05-29_07h12_12

Spring MVC Config

mvc-template1
This is my imagination of MVC model visualized:

    Model (Bean Object)
    View (JSP = magnifying glass)
    Controller (I personally don’t play a video game because it’s wasting time)

The term of “Spring MVC” is almost symbolized as J2EE Web Apps on Spring Framework. Today’s one of most popular J2EE framework. Compared to Struts, Spring is much easier for screen transition because it is not strongly tied with XML file such as struts-config.xml in Struts. Spring is a framework that try to decouple its between Model, View, and Controller.

There are three major XML files you will deal with:

spring-mvc-config-xmls1

web.xml

  • Context as root-context.xml (line 4)
  • Servlet as servlet-context.xml (line 18)
  • URL pattern (line 25)

servlet-context.xml

This is the file you have to deal with most often that defines all following info.

  • Defines Spring bean for Dependency Injection (DI) and Aspect Oriented (AOP)
  • DB config (Hibernate)

NOTE: There is other file root-context.xml. This can be empty for Spring MVC because it is used for non-web beans.


pom.xml

  • XML file for Apache Maven that defines all JAR files for this entire project

<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Processes application requests -->
<servlet>
	<servlet-name>appServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>
	
<servlet-mapping>
	<servlet-name>appServlet</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans 
    xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/mvc         http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/context     http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/security     http://www.springframework.org/schema/security/spring-security-3.2.xsd
        http://www.springframework.org/schema/tx         http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"
        >

    <!-- Enables the Spring MVC @Controller -->
    <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"/>
    
    <!-- Configure Aspect Beans, without this Aspects advices wont execute -->
    <beans:bean name="aopAnnotationAspect" class="com.ns.spring.aop.AopAnnotationAspect" />
    <beans:bean name="aopByXmlConfig"  class="com.ns.spring.aop.advise.AopByXmlConfig" />
    <!-- Configure Beans for AOP -->
    <beans:bean name="rmaController"  class="com.ns.spring.RmaController" />
        
    <beans:bean name="aopTest" class="com.ns.spring.aop.test.AopTest">
        <beans:property name="name" value="Test123"></beans:property>
    </beans:bean>

    <!-- Configure EmployeeService bean -->
    <!-- "ref": Referencing a different bean (could be in a different XML file)    -->
    <beans:bean name="aopTestService" class="com.ns.spring.aop.test.AopTestService" scope="prototype">
        <beans:property name="aopTest" ref="aopTest"></beans:property>
    </beans:bean>

    <!-- AOP Config by XML-->
    <aop:config>
        <aop:aspect ref="aopByXmlConfig" id="aspectXMLConfigID" order="1">
            <aop:pointcut expression="execution(* com.ns.spring.aop.test.AopTest.getName())" id="getNamePointcut"/>
            <aop:around method="aopAroundAdvice" pointcut-ref="getNamePointcut" arg-names="proceedingJoinPoint"/>
        </aop:aspect>
    </aop:config>

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    </beans:bean>

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
        up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
        in the /WEB-INF/views directory -->
    <beans:bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <beans:bean id="dataSource" 
        class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <beans:property name="url"      value="jdbc:mysql://localhost:3306/ns201501" />
        <beans:property name="username" value="root" />
        <beans:property name="password" value="nobu" />
    </beans:bean>

    <!-- Hibernate 4 SessionFactory Bean definition -->
    <beans:bean id="hibernate4AnnotatedSessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <beans:property name="dataSource" ref="dataSource" />
        <beans:property name="annotatedClasses">
            <beans:list>
                <beans:value>com.ns.spring.model.RMA_HDR</beans:value>
                <beans:value>com.ns.spring.model.RMA_LINE</beans:value>
                <beans:value>com.ns.spring.model.RTRN_TP</beans:value>
                <beans:value>com.ns.spring.model.RTRN_RSN</beans:value>
                <beans:value>com.ns.spring.model.RTRN_TP_RSN</beans:value>
                <beans:value>com.ns.spring.model.RTRN_TP_RSN_CMBN</beans:value>
                <beans:value>com.ns.spring.model.RMA_HDR_STS</beans:value>
                <beans:value>com.ns.spring.model.MDSE</beans:value>
                <beans:value>com.ns.spring.model.RmaLinePk</beans:value>
                <beans:value>com.ns.spring.model.RtrnTpRsnPk</beans:value>                                
                <beans:value>com.ns.spring.model.ui.RmaHdrModel</beans:value>
                <beans:value>com.ns.spring.model.ui.RmaHdrStsModel</beans:value>
                <beans:value>com.ns.spring.model.ui.RmaLineModel</beans:value>
                <beans:value>com.ns.spring.model.ui.RtrnRsnModel</beans:value>
                <beans:value>com.ns.spring.model.ui.RtrnTpModel</beans:value>
            </beans:list>
        </beans:property>
        <beans:property name="hibernateProperties">
            <beans:props>
                <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</beans:prop>
                <beans:prop key="hibernate.show_sql">true</beans:prop>
            </beans:props>
        </beans:property>
    </beans:bean>
</beans:beans>    
<?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/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.ns.spring</groupId>
   <artifactId>NS2015V07</artifactId>
   <name>NS2015V07</name>
   <packaging>war</packaging>
   <version>1.0.0-BUILD-SNAPSHOT</version>
   <properties>
      <java-version>1.7</java-version>
      <org.springframework-version>4.0.3.RELEASE</org.springframework-version>
      <org.aspectj-version>1.7.4</org.aspectj-version>
      <org.slf4j-version>1.7.5</org.slf4j-version>
      <hibernate.version>4.3.5.Final</hibernate.version>
      <jackson.databind-version>2.2.3</jackson.databind-version>
   </properties>
   <dependencies>
      <!-- Spring -->
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-context</artifactId>
         <version>${org.springframework-version}</version>
         <exclusions>
            <!-- Exclude Commons Logging in favor of SLF4j -->
            <exclusion>
               <groupId>commons-logging</groupId>
               <artifactId>commons-logging</artifactId>
            </exclusion>
         </exclusions>
      </dependency>
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-webmvc</artifactId>
         <version>${org.springframework-version}</version>
      </dependency>
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-tx</artifactId>
         <version>${org.springframework-version}</version>
      </dependency>
      <!-- Hibernate -->
      <dependency>
         <groupId>org.hibernate</groupId>
         <artifactId>hibernate-core</artifactId>
         <version>${hibernate.version}</version>
      </dependency>
      <dependency>
         <groupId>org.hibernate</groupId>
         <artifactId>hibernate-entitymanager</artifactId>
         <version>${hibernate.version}</version>
      </dependency>
      <!-- Apache Commons DBCP -->
      <dependency>
         <groupId>commons-dbcp</groupId>
         <artifactId>commons-dbcp</artifactId>
         <version>1.4</version>
      </dependency>
      <!-- MySQL -->
      <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>5.1.9</version>
      </dependency>
      <!-- Spring ORM -->
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-orm</artifactId>
         <version>${org.springframework-version}</version>
      </dependency>
      <!-- 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>
      <!-- Logging -->
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>${org.slf4j-version}</version>
      </dependency>
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>jcl-over-slf4j</artifactId>
         <version>${org.slf4j-version}</version>
         <scope>runtime</scope>
      </dependency>
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-log4j12</artifactId>
         <version>${org.slf4j-version}</version>
         <scope>runtime</scope>
      </dependency>
      <dependency>
         <groupId>log4j</groupId>
         <artifactId>log4j</artifactId>
         <version>1.2.15</version>
         <exclusions>
            <exclusion>
               <groupId>javax.mail</groupId>
               <artifactId>mail</artifactId>
            </exclusion>
            <exclusion>
               <groupId>javax.jms</groupId>
               <artifactId>jms</artifactId>
            </exclusion>
            <exclusion>
               <groupId>com.sun.jdmk</groupId>
               <artifactId>jmxtools</artifactId>
            </exclusion>
            <exclusion>
               <groupId>com.sun.jmx</groupId>
               <artifactId>jmxri</artifactId>
            </exclusion>
         </exclusions>
         <scope>runtime</scope>
      </dependency>
      <!-- @Inject -->
      <dependency>
         <groupId>javax.inject</groupId>
         <artifactId>javax.inject</artifactId>
         <version>1</version>
      </dependency>
      <!-- Servlet -->
      <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>servlet-api</artifactId>
         <version>2.5</version>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>javax.servlet.jsp</groupId>
         <artifactId>jsp-api</artifactId>
         <version>2.1</version>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>jstl</artifactId>
         <version>1.2</version>
      </dependency>
      <!-- Test -->
      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.7</version>
         <scope>test</scope>
      </dependency>
      <!-- JSON -->
      <dependency>
         <groupId>com.googlecode.json-simple</groupId>
         <artifactId>json-simple</artifactId>
         <version>1.1.1</version>
      </dependency>
      <dependency>
         <groupId>com.google.code.gson</groupId>
         <artifactId>gson</artifactId>
         <version>2.3.1</version>
      </dependency>
      <!-- Jersey -->
      <dependency>
         <groupId>asm</groupId>
         <artifactId>asm</artifactId>
         <version>3.3.1</version>
      </dependency>
      <dependency>
         <groupId>com.sun.jersey</groupId>
         <artifactId>jersey-bundle</artifactId>
         <version>1.18.1</version>
      </dependency>
      <dependency>
         <groupId>org.json</groupId>
         <artifactId>json</artifactId>
         <version>20140107</version>
      </dependency>
      <dependency>
         <groupId>com.sun.jersey</groupId>
         <artifactId>jersey-core</artifactId>
         <version>1.18.1</version>
      </dependency>
      <!-- Jackson -->
      <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-databind</artifactId>
         <version>${jackson.databind-version}</version>
      </dependency>
      <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-databind</artifactId>
         <version>2.5.0</version>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <artifactId>maven-eclipse-plugin</artifactId>
            <version>2.9</version>
            <configuration>
               <additionalProjectnatures>
                  <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
               </additionalProjectnatures>
               <additionalBuildcommands>
                  <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
               </additionalBuildcommands>
               <downloadSources>true</downloadSources>
               <downloadJavadocs>true</downloadJavadocs>
            </configuration>
         </plugin>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
               <source>1.7</source>
               <target>1.7</target>
               <compilerArgument>-Xlint:all</compilerArgument>
               <showWarnings>true</showWarnings>
               <showDeprecation>true</showDeprecation>
            </configuration>
         </plugin>
         <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.2.1</version>
            <configuration>
               <mainClass>org.test.int1.Main</mainClass>
            </configuration>
         </plugin>
      </plugins>
      <finalName>${project.artifactId}</finalName>
   </build>
</project>

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.

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