'카테고리 리스트'데이터를 뷰(View)로 전송하여, 사용자가 카테고리를 선택할 수 있도록 전송받은 데이터 가공한 뒤 출력하는 방법이 있습니다. 첫 번째는 작가 목록 구현때와 같이 리스트 데이터를 객체 통째로 전달하는 방법으로 뷰에서는 넘겨받은 데이터를 JSTL코드를 통해 조건을 부여하여 출력시킬 수 있을 것입니다. 두 번째 방법은 케터고리 리스트 데이터를 JSON타입으로 변환하여 뷰(view)로 넘기는 것입니다. 뷰(view)에선 Javascript를 통해 전달받은 JSOn타입의 데이터를 가공하여 출력시킬 수 있습니다.
2개의 방법중 JSON타입으로 변환하는 방식으로 구현하고자 합니다. 자바의 객체 데이터를 JSON으로 변환시켜주는 라이브러리 Jackson을 활용할 것입니다.
카테고리 리스트 객체를 DB로부터 호출할 수 있도록 Mapper, Service메서드를 먼저 만들 것입니다. 데이터를 반환받는 방식은 게시판의 모록 데이터를 가져오는 방식처럼 List방식을 사용합니다. 먼저 카테고리 테이블(test_bcate)의 데이터를 저장할 그릇이 VO클래스부터 작성 후 Mapper,Service순으로 작업합니다.
com.test.model패키지에 CateVO.java클래스를 생성한 뒤 아래의 변수를 추가하고 Lombok을 사용해 @Getter / @Setter / @ToString을 추가해줍니다.
@Getter
@Setter
@ToString
public class CateVO {
/* 카테고리 등급 */
private int tier;
/* 카테고리 이름 */
private String cateName;
/* 카테고리 넘버 */
private String cateCode;
/* 상위 카테고리 */
private String cateParent;
}
카테고리 리스트 데이터를 요청할 메서드를 작성합니다.
/* 카테고리 리스트 */
public List<CateVO> cateList();
AdminMapper 인터페이스에 추가한 메서드가 실행할 쿼리문을 작성합니다. test_bcate테이블의 모든 리스트를 코드번호(catecode) 번호순으로 출력되도록 쿼리문을 작성하였습니다.
<!-- 카테고리 리스트 -->
<select id="cateList" resultType="com.test.model.CateVO">
select * from test_bcate order by catecode
</select>
추가한 Mapper 메서드를 호출할 메서드 선언부를 작성합니다.
/* 카테고리 리스트 */
public List<CateVO> cateList();
오버라이딩하여 AdminServiceImpl인터페이스에서 선언한 메서드의 구현부를 완성해줍니다.
@Override
public List<CateVO> cateList() {
log.info("(service)cateList......");
return adminMapper.cateList();
}
우리는 카테고리 리스트 데이터를 'goodsEnroll.jsp'에 전달해주어야하기 때문에 해당 url매핑 메서드에 카테고리 리스트 데이터를 반환하는 Service메서드를 호출하여 'list'에 저장합니다.
List list = adminService.cateList();
우리는 카테고리 리스트 데이터를 담고 있는 객체인 'list'가 있습니다. 이제 해당 객체를 JSON형식의 String데이터로 변환해야합니다.
pom.xml에 Jackson-databind라이브러리 코드를 추가해줍니다.
<!-- JSON변환 Jackson-databind 라이브러리 추가 -->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
우리가 사용할 Jackson-databind의 메서드는 static메서드가 아니기 때문에 바로 사용할 수는 없습니다.
/* 상품 등록 페이지 접속 */
@RequestMapping(value="goodsEnroll", method=RequestMethod.GET)
public void goodsManageGET(Model model) throws Exception {
logger.info("상품 등록 페이지 접속");
ObjectMapper objm = new ObjectMapper();
List list = adminService.cateList();
String cateList = objm.writeValueAsString(list);
model.addAttribute("cateList", cateList);
}
카테고리를 출력시킬 기본적인 틀로서 <select>, <option>태그를 추가합니다. '책 카테고리'에 있던 기존의 <input>태그를 지우고 아래의 코드를 삽입합니다.
사용자가 '대분류'를 선택하게 되면 그에 맞는 '중분류'<option>이 세팅이 되고, '중분류'를 선택하면 그에 맞는 '소분류'<option>태그가 세팅하게 됩니다. 그리고 '소분류'를 선택하는 것은 상품 등록에 필요로 한 "cateCode"데이터를 선택하는 것이기 때문에 '소분류'의 <select>태그에 name속성을 부여하였습니다.
<div class="cate_wrap">
<span>대분류</span>
<select class="cate1">
<option selected value="none">선택</option>
</select>
</div>
<div class="cate_wrap">
<span>중분류</span>
<select class="cate2">
<option selected value="none">선택</option>
</select>
</div>
<div class="cate_wrap">
<span>소분류</span>
<select class="cate3" name="cateCode">
<option selected value="none">선택</option>
</select>
</div>
추가한 태그들에 css설정을 추가해주기 위해 'goodsEnroll.css'파일에 아래의 코드를 추가해줍니다.
.form_section_content select { /* 카테고리 css 설정 */
width: 92%;
height: 35px;
font-size: 20px;
text-align-last: center;
margin-left: 5px;
}
.cate_wrap span {
font-weight: 600;
}
.cate_wrap:not(:first-child) {
margin-top: 20px;
}
현재의 'cateList'객체에는 '대분류', '중분류', '소분류'모두 섞여 있는 상태입니다. 이 객체를 각 등급(tier)에 맞게 분류하여 배열에 저장시킬 것입니다. 각 배열에는 'cateName', 'cateCode', 'cateParent'변수와 그 값을 가지고 있는 객체가 저장될 것입니다.
서버로부터 전달받은 JSON데이터를 Javascript가 바로 사용할 수는 없습니다. JSON데이터를 Javascript객체로 변환해주어야 합니다. Javascript에서는 JSON문자열 데이터를 Javascript객체로 변환해주는 메서드를 제공하고 있습니다.
Javscript객체 변환 메서드
위 링크의 메서드를 활용하여 "cateList" 속성에 담긴 JSON데이터를 객체로 변환해주어 'cateList'변수에 저장합니다.
let cateList = JSON.parse('${cateList}');
/* 카테고리 */
let cateList = JSON.parse('${cateList}');
let cate1Array = new Array();
let cate2Array = new Array();
let cate3Array = new Array();
let cate1Obj = new Object();
let cate2Obj = new Object();
let cate3Obj = new Object();
let cateSelect1 = $(".cate1");
let cateSelect2 = $(".cate2");
let cateSelect3 = $(".cate3");
/* 카테고리 배열 초기화 메서드 */
function makeCateArray(obj,array,cateList, tier){
for(let i = 0; i < cateList.length; i++){
if(cateList[i].tier === tier){
obj = new Object();
obj.cateName = cateList[i].cateName;
obj.cateCode = cateList[i].cateCode;
obj.cateParent = cateList[i].cateParent;
array.push(obj);
}
}
}
/* 배열 초기화 */
makeCateArray(cate1Obj,cate1Array,cateList,1);
makeCateArray(cate2Obj,cate2Array,cateList,2);
makeCateArray(cate3Obj,cate3Array,cateList,3);
'for'문과 Jquery의 'append'를 이용해서 <select>태그 내부에 <option>태그를 추가해줄 것입니다. <script>태그 내부에 아래의 Javascript코드를 추가합니다.
/* 대분류 <option> 태그 */
for(let i = 0; i < cate1Array.length; i++){
cateSelect1.append("<option value='"+cate1Array[i].cateCode+"'>" + cate1Array[i].cateName + "</option>");
}
메서드 내에서 처리할 작업의 순서는 다음과 같습니다.
대분류 선택값 가져오기
=> 중분류 <option>태그 모두 지우기
=> 중분류 기본 <option>태그 추가
=> 대분류 선택 값과 일치하는 'cateParent'값을 가진 중분류 <option> 태그 출력
굳이 <option>태그를 모두 지우고 다시 추가하는 이유는 사용자가 대분류 선택하고 다시 다른 대분류를 선택했을 때 기존의 <option>태그들을 없애기 위함입니다.
중분류 <select>태그에 <option>태그를 추가되도록 해야 하는데, 대분류의 옵션이 선택되었을 때 출력이 되어야 합니다.
/* 중분류 <option> 태그 */
$(cateSelect1).on("change",function(){
let selectVal1 = $(this).find("option:selected").val();
cateSelect2.children().remove();
cateSelect2.append("<option value='none'>선택</option>");
for(let i = 0; i < cate2Array.length; i++){
if(selectVal1 === cate2Array[i].cateParent){
cateSelect2.append("<option value='"+cate2Array[i].cateCode+"'>" + cate2Array[i].cateName + "</option>");
}
}
});
메서드 내에서 처리할 작업의 순서는 다음과 같습니다.
중분류 선택값 가져오기
=> 소분류 <option>태그 모두 지우기
=> 소분류 기본 <option>태그 추가
=> 중분류 선택 값과 일치하는 'cateParent'값을 가진 소분류 <option> 태그 출력
소분류도 중분류와 동일한 형태의 코드를 작성해야 합니다. 소분류 <option>태그가 출력되어야 할 시점은 중분류를 선택하였을 때입니다.
/* 소분류 <option>태그 */
$(cateSelect2).on("change",function(){
let selectVal2 = $(this).find("option:selected").val();
cateSelect3.children().remove();
cateSelect3.append("<option value='none'>선택</option>");
for(let i = 0; i < cate3Array.length; i++){
if(selectVal2 === cate3Array[i].cateParent){
cateSelect3.append("<option value='"+cate3Array[i].cateCode+"'>" + cate3Array[i].cateName + "</option>");
}
}
});
현재의 코드에는 문제가 하나 있습니다. 대분류, 중분류, 소분류 순으로 선택을 한 뒤 다시 대분류를 선택을 하게 되면 중분류는 정상적으로 기존의 코드가 없어지고 기본 <option>태그가 출력이 되는데 소분류는 기존의 <option>태그가 그대로 있습니다.
이는 중분류 선택이 변경되었을 때만 소분류가 초기화되도록 작성하였기 때문입니다. 이를 해결하기 위해선 대분류가 변경되었을 때도 소분류가 초기화 되도록 코드를 추가해주어야합니다. 중분류 <option>태그를 출력하는 메서드에 아래의 코드를 추가해줍니다.
cateSelect3.children().remove();
cateSelect3.append("<option value='none'>선택</option>");