Kim VamPa

[Spring][쇼핑몰 프로젝트][31] 검색 구현(조건 검색 적용 -3) 본문

스프링 프레임워크/쇼핑몰 프로젝트

[Spring][쇼핑몰 프로젝트][31] 검색 구현(조건 검색 적용 -3)

Kim VamPa 2021. 9. 2. 22:44
728x90
반응형
프로젝트 Github : https://github.com/sjinjin7/Blog_Project
프로젝트 포스팅 색인(index) : https://kimvampa.tistory.com/188

 

목표

조건 검색을 위해 기존 검색 쿼리를 동적 쿼리로 변환

 

 저번 포스팅에서 작성한 동적 쿼리를 JUnit을 통해 테스트해보고 문제가 있는 부분을 수정할 것이고 최종적으로는 뷰에서 직접 검색을 요청하여 테스트하는 것을 목표로 합니다.

 

 

 

 

순서

1. 테스트(Junit)

2. 문제점 및 보완

3. 뷰 처리 및 테스트

4. MySQL 쿼리문 수정(2021-09-08)

 

 

 

 

1. 테스트(JUnit)

 앞의 포스팅에서 작성한 Mapper 메서드(동적 쿼리 적용)를 Junit 테스트해보겠습니다. 조건이 부여되었을 때 실행되어야 할 쿼리문이 달라지는 만큼, 5가지 상황에 따라 Mapper 메서드가 정상 동작하는지를 테스트해보겠습니다.

 

 5개 테스트를 위해 공통적으로 사용할 로직은 다음과 같습니다.

 

		Criteria cri = new Criteria();
		String type = "";
		String keyword = "";
		String catecode = "";
		
		cri.setType(type);
		cri.setKeyword(keyword);
		cri.setAuthorArr(mapper.getAuthorIdList(keyword));
		cri.setCateCode(catecode);
		
		List<BookVO> list = mapper.getGoodsList(cri);
		
		System.out.println("cri : " + cri);
		System.out.println("list : " + list);

 

 상단의 4개 줄의 코드는 Crteria클래스를 객체화시키고, 조건에 주어질 데이터를 부여해주는 코드입니다.

중 간의 4개의 코드는 조건으로 부여될 코드를 객체화한 Crteria에 담는 과정이며, 그다음의 코드는 이를 통해 조검 검색 쿼리를 수행하는 Mapper 메서드를 요청하는 코드입니다. 마지막은 Criterai 객체에 담긴 데이터와 검색 결과로 반환받은 데이터를 확인하기 위한 코드입니다.

 

 위의 코드를 기반으로 각 상황(A, C, T, AC, CT)에 따라 테스트할 수 있도록 BookMapperTests.java 클래스에 아래와 같이 코드를 작성하여 테스트를 하였습니다. 부여한 데이터는 검색 대상이 있는 데이터들로만 부여를 하였습니다. 각 코드를 테스트하여 Mapper 메서드가 정상 동작하는지 확인합니다.

 

	/* 검색 (동적 쿼리 적용) - 작가*/
	
	@Test 
	public void getGoodsListTest1() {
		//
		Criteria cri = new Criteria();
		String type = "A";
		String keyword = "유홍준";		// DB에 등록된 작가 데이터
        String keyword = "없음";		// DB에 등록되지 않은 작가 데이터
		String catecode = "";
		
		cri.setType(type);
		cri.setKeyword(keyword);
		cri.setAuthorArr(mapper.getAuthorIdList(keyword));
		cri.setCateCode(catecode);
		
		List<BookVO> list = mapper.getGoodsList(cri);
		
		System.out.println("cri : " + cri);
		System.out.println("list : " + list);
		
	}
	
	
	
	
	/* 검색 (동적 쿼리 적용) - 책제목*/
	
	@Test 
	public void getGoodsListTest2() {
		Criteria cri = new Criteria();
		String type = "T";
		String keyword = "테스트";			// 테이블에 등록된 책 제목 데이터
		//String keyword = "없음";				// 테이블에 등록되지 않은 데이터
		String catecode = "";	
		
		cri.setType(type);
		cri.setKeyword(keyword);
		cri.setAuthorArr(mapper.getAuthorIdList(keyword));
		cri.setCateCode(catecode);
		
		List<BookVO> list = mapper.getGoodsList(cri);
		
		System.out.println("cri : " + cri);
		System.out.println("list : " + list);
		
	}
	
	
	/* 검색 (동적 쿼리 적용) - 카테고리*/
	
	@Test 
	public void getGoodsListTest3() {
		Criteria cri = new Criteria();
		String type = "C";
		String keyword = "";
		String catecode = "103002";		
		
		cri.setType(type);
		cri.setKeyword(keyword);
		cri.setAuthorArr(mapper.getAuthorIdList(keyword));
		cri.setCateCode(catecode);
		
		List<BookVO> list = mapper.getGoodsList(cri);
		
		System.out.println("cri : " + cri);
		System.out.println("list : " + list);
	}
	
	
	
	/* 검색 (동적 쿼리 적용) - 카테고리 + 작가 */
	
	@Test 
	public void getGoodsListTest4() {
		Criteria cri = new Criteria();
		String type = "AC";
		String keyword = "유홍준";	// 카테고리에 존재하는 작가
		//String keyword = "머스크";	// 카테고리에 존재하지 않는 작가
		String catecode = "103002";
		
		cri.setType(type);
		cri.setKeyword(keyword);
		cri.setAuthorArr(mapper.getAuthorIdList(keyword));
		cri.setCateCode(catecode);
		
		List<BookVO> list = mapper.getGoodsList(cri);
		
		System.out.println("cri : " + cri);
		System.out.println("list : " + list);	
		
	}
	
	
	
	
	/* 검색 (동적 쿼리 적용) - 카테고리 + 책 제목 */
	
	@Test 
	public void getGoodsListTest5() {
		Criteria cri = new Criteria();
		String type = "CT";			// 카테고리에 존재하는 책
		String keyword = "테스트";	// 카테고리에 존재하지 않는 책
		//String keyword = "없음";
		String catecode = "102001";
		
		cri.setType(type);
		cri.setKeyword(keyword);
		cri.setAuthorArr(mapper.getAuthorIdList(keyword));
		cri.setCateCode(catecode);
		
		List<BookVO> list = mapper.getGoodsList(cri);
		
		System.out.println("cri : " + cri);
		System.out.println("list : " + list);	
		
	}

 

그림 1-1

 

Junit 테스트 결과는 아래와 같습니다. 

 

 

그림 1-2 작가 검색(유홍준)

 

그림 1-3 책 제목 검색(테스트)

 

그림 1-4 카테고리 검색(103002)

 

그림 1-5 작가 + 카테고리(유홍준, 103002)

 

그림 1-6 책 제목 + 카테고리(테스트, 102001)

 

 

2. 문제점 및 보완

 

 그런데 테스트 결과 중 의도하지 않는 결과가 나오는 코드들이 있습니다. 작가 검색 조건이 들어가는 코드들입니다. 

 

 책 제목 검색, 카테고리 검색의 경우 조건에 맞지 않은 데이터를 부여한 경우에는 아래와 같이 결과가 검색되지 않습니다.

 

그림 2-1 책 제목 검색 - 없는데이터("없음")

 

그림 2-2 결과

 

 

 하지만 작가 검색 조건이 있는 경우(A, AC)에는 아래와 같이 검색조건과 상관없는 책 데이터들이 뜹니다.

 

그림 2-4 카테고리 + 작가 , 없는 데이터("머스크")

 

그림 2-5 결과

 

그림 2-4 작가 , 없는 데이터("머스크")

 

그림 2-6 결과

 

 

 작가 정보의 경우 getAuthorIdList() Mapper 메서드로부터 반환받은 데이터를 활용해서 동적 쿼리에 사용이 되는데, 작가 정보가 없는 경우 요소가 없는 빈 배열 객체가 MyBatis 쿼리문에 전달되어서 작가 조건문이 추가되지 않은 쿼리문이 사용되게 되기 때문입니다.

 

그림 2-7 작가 + 카테고리 쿼리(빈 배열을 전달 받아서 작가 조건문이 없음)

 

 

 MyBatis쿼리문에 <if> 혹은 <choose>, <when> 태그를 추가하여 보완을 해줄 수도 있겠지만,  getAuthorIdList() Mapper 메서드의 결과가 요소가 없는 빈 배열을 반환하게 된다면 검색 쿼리 결과도 없어야 하는 것이기 때문에 Service 단계에서 getAuthorIdList() 메서드가 빈 배열을 반환할 시 Controller에 요소가 없는 빈 List를 반환하도록 코드를 수정해주겠습니다.

 

 BookMapperServiceImpl.java 클래스의 getGoodsList() 메서드의 구현부를 아래와 같이 수정해줍니다.

 

		log.info("getGoodsList().......");
		
		String type = cri.getType();
		String[] typeArr = type.split("");
		String[] authorArr = bookMapper.getAuthorIdList(cri.getKeyword());
		
		
		if(type.equals("A") || type.equals("AC") || type.equals("AT") || type.equals("ACT")) {
			if(authorArr.length == 0) {
				return new ArrayList();
			}
		}
		
		for(String t : typeArr) {
			if(t.equals("A")) {
				cri.setAuthorArr(authorArr);
			}
		}		
		
		return bookMapper.getGoodsList(cri);

 

그림 2-8

 

 

 수정된 쿼리의 흐름을 보면 '작가 배열 정보'를 authorArr 변수에 저장해 두고 조건이 '작가'를 포함하고 authorArr이 빈 배열 데이터일 경우 Controller에 요소가 없는 빈 List를 반환합니다. 빈 리스트 배열이 아닌 경우 해당 배열의 데이터를 Criterai의 authorArr 변수에 담은 뒤 검색 쿼리(getGoodsList())를 실행하게 됩니다.

 

 

3. 뷰 처리 및 테스트

 조건 검색을 사용할 수 있도록 main.jsp에 코드를 추가 해준 뒤 조건 검색을 테스트해보겠습니다. 검색 부분(search_warp) 태그에 사용자가 조건을 적용할 수 있도록 <select> 태그와 <option> 태그를 아래와 같이 추가해줍니다.

 

                				<select name="type">
                					<option value="T">책 제목</option>
                					<option value="A">작가</option>
                				</select>

 

그림 2-9

 

서버를 구동시켜서 테스트를 진행해봅니다. 

 

그림 3-1

 

그림 3-2

 

 

그림 3-3

 

그림 3-4

 

 AC와 AT 복합 조건을 테스트해보고 싶으시다면 URL의 쿼리 스트링을 통해서 테스트를 해보시면 됩니다.

 

그림 3-5

 

그림 3-6

 

4. MySQL 쿼리문 수정(2021-09-08)

 MySQL 프로젝트의 쿼리문에서 리스트를 가져오는(getGoodsList)는 문제가 없지만 리스트의 총 갯수(goodsGetTotal)를 가져오는 쿼리문이 현재 에러가 납니다. 

 

 getGoodsList에서 3개의 테이블을 Join으로 하기때문에 테이블의 이름쉽게 쓰기 위해서 테이블에 별칭 a,b,c를 주었습니다.

 

그림 4-1

 

따라서 getGoodsList와 goodsGetTotal 공용으로 사용하는 쿼리문(sql태그에) authorId를 a.authorId로 작성을 하였습니다.

 

그림 4-2

 

 그런데 goodsGetTotal쿼리문에는 이 쿼리문을 사용할 경우 a라고 지칭한 테이블이 없기 때문에 에러가 발생을 합니다.

 

그림 4-3

 

따라서 goodsGetTotal 쿼리문의 테이블에도 a라는 별칭을 추가해주었습니다. 

 

그림 4-4

 

 

 

 

 

REFERENCE

  • 코드로배우는 스프링 웹 프로젝트(남가람북스)
  •  

 

 

 

DATE

  • 2020.09.02

 

728x90
반응형
Comments