Java 프레임워크 만들기 - JSP

자바 어노테이션으로 데이터 액세스 객체 만들기 3 - Java Annotation DAO(Data Access Object), 이클립스(Eclipse)

carrotweb 2021. 6. 2. 11:08
728x90
반응형

지금 까지 로그인 처리를 위해 다오(DAO), 서비스(Service), 컨트롤러(Controller)를 생성하였습니다.

"ServletContextListener"에서 다오(DAO) 클래스를 사용할 수 있게 의존성 주입(Dependency Injection - DI)를 하겠습니다.

이전 "자바 데이터베이스 매니저 만들기 2"를 통해 데이터베이스매핑맵(databaseMappingMap)을 추가하였습니다.

// DBId-Database 맵
Map<String, TestDatabaseManager> databaseMappingMap = new HashMap<String, TestDatabaseManager>();

String databaseManagers = sce.getServletContext().getInitParameter("DatabaseManager");
if (databaseManagers != null && !databaseManagers.trim().isEmpty()) {
	String[] databaseManagerPaths = databaseManagers.trim().split("\n|,|;|\\s+");
	for (String databaseManagerPath : databaseManagerPaths) {
		databaseManagerPath = databaseManagerPath.trim();
		if (!databaseManagerPath.isEmpty()) {
			TestDatabaseManager testDatabaseManager = new TestDatabaseManager(databaseManagerPath);
			if (testDatabaseManager.isInitDriver()) {
				databaseMappingMap.put(testDatabaseManager.getId(), testDatabaseManager);
			}
		}
	}
}

 

11. "TestServletContextListener.java"의 "contextInitialized"에 DAO 클래스에 대한 의존성 주입을 위해 저장소매핑맵(repositoryMappingMap)을 추가합니다.

// Repository-Class 맵
Map<String, Object> repositoryMappingMap = new HashMap<String, Object>();

"@TestAnnRepository"어노테이션이 적용된 DAO 클래스를 스캔하여 인스턴스를 생성하고 DAO 클래스의 인터페이스(interface)와 생성된 인스턴스를 저장소매핑맵(repositoryMappingMap)에 추가합니다.

for (Class<?> findClass : classes) {
	TestAnnRepository annoRepository = findClass.getAnnotation(TestAnnRepository.class);
	if (annoRepository != null) {
		Object repositoryeInstance = null;
		try {
			repositoryeInstance = findClass.newInstance();
			Class<?>[] interfaces = findClass.getInterfaces();
			for (int i = 0; i < interfaces.length; ++i) {
				repositoryMappingMap.put(interfaces[i].getName(), repositoryeInstance);
				System.out.println("[Repository] " + findClass.getName() + " 인스턴스를 생성함");
			}
		} catch (InstantiationException | IllegalAccessException e) {
			//e.printStackTrace();
			System.out.println(findClass.getName() + "의 인스턴스를 생성하지 못함");
		}
	}
}

그리고 생성된 인스턴스에서 선언된 맴버 필드 리스트를 가져와서 "@TestAnnAutowired"어노테이션과 "@TestAnnQualifier"어노테이션이 있는지 확인합니다.

Field[] Fields = findClass.getDeclaredFields();
for (Field field : Fields) {
	TestAnnAutowired testAnnAutowired = field.getAnnotation(TestAnnAutowired.class);
	TestAnnQualifier testAnnQualifier = field.getAnnotation(TestAnnQualifier.class);
	if (testAnnAutowired != null && testAnnQualifier != null) {
	}
}

맴버 필드의 타입으로 데이터베이스매핑맵(databaseMappingMap)에서 ID와 일치하는 데이터베이스 매니저 클래스를 가져옵니다.

TestDatabaseManager testDatabaseManager = (TestDatabaseManager) databaseMappingMap.get(testAnnQualifier.value());
if (testDatabaseManager != null) {
}

맴버 필드에 접근할 수 있게 설정하고 "set"메소드를 통해 값을 주입(인젝션)합니다.

field.setAccessible(true);
try {
	field.set(repositoryeInstance, testDatabaseManager);
} catch (IllegalArgumentException | IllegalAccessException e) {
	e.printStackTrace();
}

전체 소스입니다.

// Repository-Class 맵
Map<String, Object> repositoryMappingMap = new HashMap<String, Object>();

for (Class<?> findClass : classes) {
	TestAnnRepository annoRepository = findClass.getAnnotation(TestAnnRepository.class);
	if (annoRepository != null) {
		Object repositoryeInstance = null;
		try {
			repositoryeInstance = findClass.newInstance();
			Class<?>[] interfaces = findClass.getInterfaces();
			for (int i = 0; i < interfaces.length; ++i) {
				repositoryMappingMap.put(interfaces[i].getName(), repositoryeInstance);
				System.out.println("[Repository] " + findClass.getName() + " 인스턴스를 생성함");
			}
		} catch (InstantiationException | IllegalAccessException e) {
			//e.printStackTrace();
			System.out.println(findClass.getName() + "의 인스턴스를 생성하지 못함");
		}

		if (repositoryeInstance != null) {
			Field[] Fields = findClass.getDeclaredFields();
			for (Field field : Fields) {
				TestAnnAutowired testAnnAutowired = field.getAnnotation(TestAnnAutowired.class);
				TestAnnQualifier testAnnQualifier = field.getAnnotation(TestAnnQualifier.class);
				if (testAnnAutowired != null && testAnnQualifier != null) {
					System.out.println("[Repository Field] " + field.getType().getName() + " 타입의 " + field.getName() + " 맴버 필드을 찾음");
					TestDatabaseManager testDatabaseManager = (TestDatabaseManager) databaseMappingMap.get(testAnnQualifier.value());
					if (testDatabaseManager != null) {
						field.setAccessible(true);
						try {
							field.set(repositoryeInstance, testDatabaseManager);
							System.out.println("[Repository Field] " + field.getName() + "에 의존성 주입을 처리함");
						} catch (IllegalArgumentException | IllegalAccessException e) {
							e.printStackTrace();
							System.out.println("[Repository Field] " + field.getName() + "에 의존성 주입을 처리하지 못함");
						}
					}
				}
			}
		}
	}
}

 

12. "TestServletContextListener.java"의 "contextInitialized"에 서비스(Service) 클래스에서 선언된 맴버 필드 리스트를 가져와서 "@TestAnnAutowired"어노테이션이 있는 DAO 인터페이스 필드에 주입(인젝션)하는 부분을 추가합니다.

// Service-Class 맵
Map<String, Object> serviceMappingMap = new HashMap<String, Object>();

for (Class<?> findClass : classes) {
	TestAnnService annoService = findClass.getAnnotation(TestAnnService.class);
	if (null != annoService) {
		Object serviceInstance = null;
		try {
			serviceInstance = findClass.newInstance();
			Class<?>[] interfaces = findClass.getInterfaces();
			for (int i = 0; i < interfaces.length; ++i) {
				serviceMappingMap.put(interfaces[i].getName(), serviceInstance);
				System.out.println("[Service] " + findClass.getName() + "서비스 인스턴스를 생성함");
			}
		} catch (InstantiationException | IllegalAccessException e) {
			//e.printStackTrace();
			System.out.println(findClass.getName() + "의 서비스 인스턴스를 생성하지 못함");
		}

		if (null != serviceInstance) {
			Field[] Fields = findClass.getDeclaredFields();
			for (Field field : Fields) {
				TestAnnAutowired testAnnAutowired = field.getAnnotation(TestAnnAutowired.class);
				if (null != testAnnAutowired) {
					System.out.println("[Service Field] " + field.getType().getName() + " 타입의 " + field.getName() + " 맴버 필드을 찾음");
					Object objectImplement = (Object) repositoryMappingMap.get(field.getType().getName());
					if (null != objectImplement) {
						field.setAccessible(true);
						try {
							field.set(serviceInstance, objectImplement);
							System.out.println("[Service Field] " + field.getName() + "에 의존성 주입을 처리함");
						} catch (IllegalArgumentException | IllegalAccessException e) {
							e.printStackTrace();
							System.out.println("[Service Field] " + field.getName() + "에 의존성 주입을 처리하지 못함");
						}
					}
				}
			}
		}
	}
}

 

 

13. "TestDispatcherServlet.java"의 "service"메소드에 "redirect"를 처리하기 위해 "response"의 "sendRedirect"메소드를 추가합니다.

if (!modelAndView.isViewNameEmpty()) {
	if (modelAndView.getViewName().startsWith("redirect:")) {
		response.sendRedirect(modelAndView.getViewName().substring(9));
	} else {
		RequestDispatcher dispatcher = request.getRequestDispatcher(modelAndView.getViewName());
		dispatcher.forward(request, response);
	}
}

 

14. "Servers"탭에서 "tomcat8"를 선택하고 "start"버튼(start the server)을 클릭합니다.

"Console"탭을 클릭하면 "@TestAnnRepository"어노테이션이 적용된 DAO 클래스의 인스턴스를 생성하고 "@TestAnnQualifier"어노테이션이 적용된 DAO 클래스 맴버 필드에 데이터베이스 매니저 클래스를 주입한 것을 확인할 수 있습니다. 그리고 서비스 클래스 맴버 필드에 DAO 클래스가 주입된 것을 확인할 수 있습니다.

[Console]

ServletContext 초기화 실행
basePackage : com.home.project.test2
데이터베이스 프로퍼티를 읽음
데이터베이스 드라이버(class org.mariadb.jdbc.Driver)가 로딩됨
[Repository] com.home.project.test2.dao.TestLoginDaoImpl 인스턴스를 생성함
[Repository Field] com.home.project.test2.database.TestDatabaseManager 타입의 testDatabaseManager 맴버 필드을 찾음
[Repository Field] testDatabaseManager에 의존성 주입을 처리함
[Service] com.home.project.test2.service.TestLoginService서비스 인스턴스를 생성함
[Service Field] com.home.project.test2.dao.ITestLoginDao 타입의 testLoginDao 맴버 필드을 찾음
[Service Field] testLoginDao에 의존성 주입을 처리함
[Service] com.home.project.test2.service.TestService1서비스 인스턴스를 생성함

 

웹 브라우저에서 "http://localhost:8080/test2/testform.do"를 입력합니다.

아이디는 "1"를 패스워드는 "1"를 입력하고 "로그인"버튼을 클릭합니다.

"Console"탭을 보면 마리아디비(MariaDB)에서 쿼리한 것을 확인할 수 있습니다.

[Console]

id : 1, password : 1
데이터베이스에 연결됨
Statement를 생성함
Query[SELECT MBR_ID, MBR_PWD, MBR_PWD_SALT, MBR_NM FROM MBR_ACCOUNT_TB WHERE MBR_ID = '1']를 실행함
Statement를 종료함
데이터베이스에서 연결을 종료함
ServletRequest에 속성 추가 - 속성명 : errorMessage, 속성 값 : 아이디/패스워드가 정확하지 않습니다.

 

정상적인 로그인을 위해 아이디는 "testid"를 패스워드는 "testpwd"를 입력하고 "로그인"버튼을 클릭합니다.

"Console"탭을 보면 마리아디비(MariaDB)에서 쿼리가 되어 "UserVO"객체가 생성되고 인증된 것을 확인할 수 있습니다.

[Console]

id : testid, password : testpwd
데이터베이스에 연결됨
Statement를 생성함
Query[SELECT MBR_ID, MBR_PWD, MBR_PWD_SALT, MBR_NM FROM MBR_ACCOUNT_TB WHERE MBR_ID = 'testid']를 실행함
Statement를 종료함
데이터베이스에서 연결을 종료함
HttpSession에 속성 추가 - 속성명 : auth, 속성 값 : com.home.project.test2.vo.UserVO@43992e24
Session Manager Count : 1, Add ID : testid, Session ID : F17C9BECD60628EBBAE72C2C6CB32B1E

 

Annotation(어노테인션)을 이용하여 "SpringFramework"와 같은 Annotation(어노테인션)기반의 MVC모델을 구성하였습니다.

728x90
반응형