Java 프레임워크 만들기 - JSP

자바 제네릭 메소드와 리플렉션을 이용한 자동 PreparedStatement 생성 3 - Java Generic Method Reflection PreparedStatement

carrotweb 2021. 7. 19. 20:39
728x90
반응형

세번째 ResultSet 객체에서 여러개의 행(row)를 받아 객체로 생성하고 리스트 객체로 전달하는 메소드인 executeQueryList()메소드를 생성하겠습니다.

PreparedStatement에서 사용되는 쿼리문

SELECT MBR_ID AS id, MBR_NM AS name FROM MBR_ACCOUNT_TB LIMIT 0, 10

쿼리문처럼 조건 없이 전체를 카운트 할 수 있어 전달되는 객체가 없을 수 있습니다.

executeQueryList()메소드는executeQueryOne()메소드와 동일하지만 결과가 리스트 객체로 전달됩니다.

데이터베이스 컨넥션 객체를 가져옵니다.

Connection connection = getConnection();

 

createPreparedStatement()메소드를 이용하여 PreparedStatement를 생성합니다.

PreparedStatement preparedStatement = createPreparedStatement(connection, query, parameterObject);
if (preparedStatement != null) {
	System.out.println("PreparedStatement를 생성함");
} else {
	System.out.println("PreparedStatement를 생성하지 못함");
}

자세한 설명은 "자바 패턴 매치와 리플렉션을 이용한 자동 PreparedStatement 생성 1"를 참조하세요.

생성된 PreparedStatement를 실행하여 ResultSet 객체를 받습니다.

ResultSet resultSet = preparedStatement.executeQuery();

 

ResultSet 객체의 전체 행(row)들을 리턴하기 위해 전달 받은 클래스로 리스트 객체를 생성합니다.

List<T> resultTypeList = new ArrayList<T>();

 

while문으로 ResultSet 객체의 전체 행(row)들을 전달 받은 클래스로 새로운 인스턴스를 생성합니다.

while (resultSet.next()) {
	T resultTypeInstance = null;
	try {
		resultTypeInstance = resultTypeClass.newInstance();
	} catch (InstantiationException | IllegalAccessException e) {
		e.printStackTrace();
	}
}

 

생성된 객체에서 맴버 필드 리스트를 가져옵니다.

Field[] Fields = resultTypeClass.getDeclaredFields();

 

ResultSet 객체에서 컬럼(column)의 메타정보를 가져옵니다.

ResultSetMetaData resultSetMetaData = resultSet.getMetaData();

 

ResultSet 객체의 컬럼과 일치하는 객체의 맴버 필드를 찾고 맴버 필드에 접근할 수 있게 설정하여 맴버 필드에 값을 설정합니다.

for (int index = 1; index <= resultSetMetaData.getColumnCount(); index++) {
	String columnLabel = resultSetMetaData.getColumnLabel(index);
	for (Field field : Fields) {
		if (field.getName().equals(columnLabel)) {
			field.setAccessible(true);
			try {
				field.set(resultInstance, resultSet.getObject(index));
			} catch (IllegalArgumentException | IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}
}

 

생성된 객체를 리스트 객체에 추가합니다.

resultTypeList.add(resultTypeInstance);

 

PreparedStatement를 종료합니다.

preparedStatement.close();

 

데이터베이스 컨넥션 객체를 반환하고 결과로 리스트 객체를 리턴합니다.

closeConnection(connection);

return resultTypeList;

 

1. "TestDatabaseDataSource.java"나 "TestDatabaseJNDI.java", "TestDatabaseConectionPool.java", "TestDatabasePoolManager.java", "TestDatabaseManager.java"에 추가하시면 됩니다.

executeQueryList()메소드에서 전달되는 클래스로 결과를 생성하여 리턴하기 위해 제네릭 메소드로 생성합니다.

추가되는 전체 소스입니다.

/**
 * 쿼리문(SELECT)을 실행한다.
 * @param query 쿼리 문자열
 * @param parameterObject 파라미터 객체
 * @param resultTypeClass 결과 클래스
 * @return 결과 값
 */
public <T> List<T> executeQueryList(String query, Object parameterObject, Class<T> resultTypeClass) {
	List<T> resultTypeList = null;

	long startTime = System.currentTimeMillis();

	Connection connection = getConnection();

	PreparedStatement preparedStatement = createPreparedStatement(connection, query, parameterObject);
	if (preparedStatement != null) {
		System.out.println("PreparedStatement를 생성함");
		try {
			ResultSet resultSet = preparedStatement.executeQuery();
			resultTypeList = new ArrayList<T>();

			if (resultTypeClass != null) {
				while (resultSet.next()) {
					T resultTypeInstance = null;
					if (resultTypeClass != null) {
						try {
							resultTypeInstance = resultTypeClass.newInstance();
						} catch (InstantiationException | IllegalAccessException e) {
							e.printStackTrace();
						}
					}

					if (resultTypeInstance != null) {
						Field[] Fields = resultTypeClass.getDeclaredFields();
						ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
						for (int index = 1; index <= resultSetMetaData.getColumnCount(); index++) {
							String columnLabel = resultSetMetaData.getColumnLabel(index);
							for (Field field : Fields) {
								if (field.getName().equals(columnLabel)) {
									field.setAccessible(true);
									try {
										field.set(resultTypeInstance, resultSet.getObject(index));
										System.out.println("객체의 " + field.getName() + "에 값(" + resultSet.getObject(index) + ")을 적용함");
									} catch (IllegalArgumentException | IllegalAccessException e) {
										e.printStackTrace();
									}
								}
							}
						}
					}
					resultTypeList.add(resultTypeInstance);
				}
				System.out.println("Query[" + preparedStatement.toString() + "]를 실행함");
			}
			resultSet.close();
		} catch (SQLException e) {
			resultTypeList = null;
			System.out.println("Query[" + preparedStatement.toString() + "]를 실행하지 못함");
			e.printStackTrace();
		}

		try {
			preparedStatement.close();
			System.out.println("PreparedStatement를 종료함");
		} catch (SQLException e) {
			System.out.println("PreparedStatement를 종료하지 못함");
			e.printStackTrace();
		}
	} else {
		System.out.println("PreparedStatement를 생성하지 못함");
	}

	closeConnection(connection);

	long endTime = System.currentTimeMillis();
	System.out.println((endTime - startTime) + "ms 소요됨");

	return resultTypeList;
}

 

 

2. "TestLoginDaoImpl.java"의 getMemberList()메소드를 executeQueryList()메소드로 처리되게 변경합니다.

@Override
public List<UserVO> getMemberList() {
	List<UserVO> list = null;

	String query = "SELECT MBR_ID AS id, MBR_NM AS name FROM MBR_ACCOUNT_TB LIMIT 0, 10";
	Connection connection = testDatabaseManager.getConnection();
	if (connection != null) {
		PreparedStatement preparedStatement = null;

		try {
			preparedStatement = connection.prepareStatement(query);
			System.out.println("PreparedStatement를 생성함");
		} catch (SQLException e) {
			System.out.println("PreparedStatement를 생성하지 못함");
			e.printStackTrace();
		}

		if (preparedStatement != null) {
			ResultSet resultSet = null;
			try {
				resultSet = preparedStatement.executeQuery();
				System.out.println("Query[" + preparedStatement.toString() + "]를 실행함");
			} catch (SQLException e) {
				System.out.println("Query[" + preparedStatement.toString() + "]를 실행하지 못함");
				e.printStackTrace();
			}

			try {
				while (resultSet.next()) {
					UserVO selectUserVO = new UserVO();
					selectUserVO.setId(resultSet.getString("MBR_ID"));
					selectUserVO.setName(resultSet.getString("MBR_NM"));
					list.add(selectUserVO);
				}
				resultSet.close();
				if (list.size() <= 0) {
						System.out.println("resultSet이 없음");
				}
			} catch (SQLException e) {
				System.out.println("resultSet를 가져오지 못함");
				e.printStackTrace();
			}

			try {
				preparedStatement.close();
				System.out.println("PreparedStatement를 종료함");
			} catch (SQLException e) {
				System.out.println("PreparedStatement를 종료하지 못함");
				e.printStackTrace();
			}
		}

		testDatabaseManager.closeConnection(connection);
	}

	return list;
}

변경된 소스입니다.

@Override
public List<UserVO> getMemberList() {
	List<UserVO> list = null;

	String query = "SELECT MBR_ID AS id, MBR_NM AS name FROM MBR_ACCOUNT_TB LIMIT 0, 10";
	list = (List<UserVO>)testDatabaseManager.executeQueryList(query, null, UserVO.class);

	return list;
}

 

3. 이전 "자바 JUnit를 이용한 단위 테스트"에서 추가한 "TestLoginDaoImplTest.java"에서 테스트 케이스인 testGetMemberList()메소드에서 getMemberList()메소드를 실행할 수 있게 수정합니다.

/**
 * Test method for {@link com.home.project.test2.dao.TestLoginDaoImpl#getMemberList()}.
 */
@Test
public void testGetMemberList() {
	System.out.println("testGetMemberList() 테스트 시작");

	List<UserVO> userList = testLoginDao.getMemberList();
	for (UserVO userVO : userList) {
		System.out.println("사용자 ID : " + userVO.getId());
		System.out.println("사용자 이름 : " + userVO.getName());
	}

	System.out.println("testGetMemberList() 테스트 성공 종료");
}

 

​4. test2 프로젝트의 [Java Resources > src/test/java]에 있는 "com.home.project.test2.util > TestLoginDaoImplTest.java"에서 마우스 오른쪽 버튼을 클릭하여 콘텍스트 메뉴에서 [Run As > JUnit Test]를 클릭합니다.

JUnit Test가 실행되면서 왼쪽에 JUnit탭이 나타나고 Error가 "0", Failures이 "0"으로 테스트가 성공합니다.

[Console]

testGetMemberList() 테스트 시작
[main] 데이터베이스 커넥션 객체[24433162, URL=jdbc:mariadb://localhost:3306/test, MariaDB Connector/J]를 가져옴
PreparedStatement를 생성함
객체의 id에 값(testid)을 적용함
객체의 name에 값(홍길동1)을 적용함
Query[sql : 'SELECT MBR_ID AS id, MBR_NM AS name FROM MBR_ACCOUNT_TB LIMIT 0, 10', parameters : []]를 실행함
PreparedStatement를 종료함
[main] 데이터베이스 커넥션 객체[24433162, URL=jdbc:mariadb://localhost:3306/test, MariaDB Connector/J]를 반환함
27ms 소요됨
사용자 ID : testid
사용자 이름 : 홍길동1
testGetMemberList() 테스트 성공 종료

 

이제 PreparedStatement 자동 생성과 실행으로 DAO에서는 쿼리문만 집중해서 작성하게 되었습니다.

또한 반복적인 코드를 줄임으로써 개발 시간이 단축되었습니다.

728x90
반응형