들어가며
- 이전 포스트에서 프론트 컨트롤러 패턴에 대한 소개와 해당 패턴을 적용할 시에 얻을 수 있는 이점에 대해 알아보았다.
- 이번에는 이 프론트 컨트롤러를 구현해 볼 것이다.
- 개발환경에 대한 설명은 이전 포스트에 적혀 있으니 이전 포스트를 참고하면 되겠다.
프론트 컨트롤러 적용 구조
- 프론트 컨트롤러를 적용하면 많은 것이 변경될 수 있지만 모든 것을 곧바로 변경시키지는 않을 것이다. 차근차근히 점진적으로 바꿔나가보는게 중요하다.
- 맨 처음에는 프론트컨트롤러를 말 그대로 적용만 시킬 것이다.
- 프론트 컨트롤러의 가장 중요한 기능 중 하나는 들어온 요청에 대해 공통 로직을 수행한 후에 요청을 처리할 수 있는 컨트롤러를 찾아 해당 컨트롤러로 요청을 위임하는 것이다.
- 당연히 이를 위해서 프론트 컨트롤러는 모든 컨트롤러에 대해 알고 있어야 한다. 즉 모든 컨트롤러에 대한 정보를 저장하고 있는 저장소가 필요하다. 이는 해당 컨트롤러가 처리 가능한 URI를 Key로, 컨트롤러 객체를 Value로 하는 Map 자료구조면 딱이다.
- 요청을 처리할 수 있는 컨트롤러를 찾았다면, 해당 컨트롤러에 요청을 위임한다. 컨트롤러는 위임받은 요청에 대해 처리를 수행한 뒤 JSP로 포워딩한다. 이후 서버에서 랜더링 된 JSP가 Http 응답으로 클라이언트에게 다시 돌아간다.
구현 - Domain, Repository 구현
- 먼저 요청을 처리할 컨트롤러부터 구현할 것이다. 많은 걸 바꾸지 않고 프론트 컨트롤러만 적용시키기로 했기 때문에 이번 포스트에서 HttpServlet 종속을 제거하는 등의 개선은 아직 수행하지 않을 것이다.
- 구현해야할 컨트롤러들은 다음과 같아야 한다.
- 회원 정보의 저장 - (Save)
- 회원 정보의 조회
- 회원들의 모든 정보 조회
- 이를 먼저 구현하기 전에 회원 데이터의 정의와 어떻게 저장할 것인지부터 먼저 구현하도록 한다.
Domain, Repository 구현
- 회원 정보는 다음과 같이 이루어진다.
- 회원의 이름(user name)
- 회원의 나이(age)
- 이를 기반으로 domain을 만들 것이다. 즉 DB 테이블을 정의하는 것이다.
- 앱이 실행되는 Main 클래스가 존재하는 곳의 패키지 내부에 domain이라는 패키지를 만든다.
- 해당 domain 클래스 파일의 의 이름은 Member로 할 것이다.
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Member{
private long id;
private String userName;
private int age;
}
- 위의 어노테이션들은 롬복에서 가져온 어노테이션들이다.
- @Data는 @Getter, @Setter, @ToString 등 자주 사용하는 롬복 어노테이션을 모아 놓은 세트이다.
- @NoArgsConstructor는 그냥 비어있는 생성자를 추가해준다.
- @AllArgsConstructor는 모든 멤버 변수를 사용한 생성자를 추가해준다.
- 이렇게 도메인 부분의 구현이 완료되었다.
- 이제 이 데이터를 어떻게 DB와 통신하여 저장할 것인가라는 것이 문제이다. 이러한 프로젝트에 DB까지 연동하는 것은 비효율적이기 때문에 메모리를 통하여 데이터를 저장하는 형식으로 할 것이다. 즉 Map을 사용하여 저장할 것이다.
- 먼저 domain 패키지가 있는 위치와 동일한 위치에 repository 패키지를 만든다.
- 이후에 멤버 객체를 저장하는 역할을 맡은 객체이기 때문에 MemberRepository라고 이름 붙일 것이다.
public class MemberRepository{
private static Map<Long, Member> store = new HashMap<>();
private static long seqId = 0L;
private static final MemberRepository instance = new MemberRepository();
public static MemberRepository getInstance(){
return instance;
}
private MemberRepository(){}
public Member save(Member member){
member.setId(++seqId);
store.put(member.getId(), member);
return member;
}
public Member findById(long id){
return store.get(id);
}
public List<Member> findAll(){
return new ArrayList<>(store.values());
}
public void clear(){
store.clear();
}
}
- 저장소는 key를 id로, value를 Member 객체로 하는 Map으로 구성하였다.
- 또한 생성자를 private로 지정하였다. 이전에 Spring Framework 파트에서도 설명한 적이 있는데 싱글톤 패턴을 통하여 repository를 구현한 것이다.
- 이는 굳이 repository 객체가 여러 개일 이유가 없기 때문에 추가적인 객체 생성을 막기 위해서 싱글톤 패턴을 적용시킨 것이다.
정리
- 글의 분량상 Domain, Repository를 구현하는 것 까지만 수행하였다. 해당 부분에 대한 설명들은 이후에 DB에 대해 설명할 때 자세히 설명하며 그냥 이런 기능을 하는 객체를 이렇게 구현했다고만 생각하고 넘어가자
- 다음 부분에서 컨트롤러 구현을 해볼 것이다. 코드는 깃허브에 저장되어 있다.
'Spring & JPA > SpringMVC' 카테고리의 다른 글
Spring MVC - MVC 구조 - 4. View의 분리 (1) | 2023.05.31 |
---|---|
Spring MVC - MVC 구조 - 3. 프론트 컨트롤러 구현(2) (0) | 2023.05.30 |
Spring MVC - MVC 구조 - 1. 프론트 컨트롤러 (0) | 2023.05.30 |
Spring MVC - 기반 지식 - 4. WAS와 리소스 반환, CSR, SSR (0) | 2023.05.26 |
Spring MVC - 기반 지식 - 3. WAS와 멀티 쓰레드 (0) | 2023.05.26 |