상세 컨텐츠

본문 제목

[스프링2] 15장. 간단한 웹 어플리케이션의 구조

22-23/22-23 Spring 2

by YUZ 유즈 2023. 2. 2. 11:14

본문

728x90

 

초보 웹 개발자를 위한 스프링5 프로그래밍 입문 15장을 다루고있습니다.


15장의 키워드

# 웹 구성 요소

# 서블릿-컨트롤러-서비스-DAO의 관계

# 패키지 구성

1. 간단한 웹 어플리케이션의 구성 요소

  • 프론트 서블릿(DispatcherServlet)
  • 컨트롤러 + 뷰
  • 서비스
  • DAO

복습

  • 프론트 서블릿(DispatcherServelt) : 서블릿 컨테이너 제일 앞단에서 서버로 오는 모든 요청을 받아 처리하는 창구 역할 컨트롤러 (252p)
  • 컨트롤러 : 사용자의 요청을 처리한 후 뷰에 모델 객체를 넘겨주는 역할 (250p)
  • 서비스 : 요청에 대해 어떤 처리를 할지 접근하는 파트(기능의 로직을 구현)
  • DAO(Data Access Object) : DB와 웹 간에 데이터를 이동시켜주는 역할(데이터베이스의 조회, 조작 가능)

 

어플리케이션 구조

DispatcherServlet   -> 컨트롤러   -> 서비스   -> DAO
  1. 프론트 서블릿은 요청을 분석해서 알맞은 컨트롤러에 전달한다.
  2. 컨트롤러는 실제 웹 브라우저 요청을 처리하고, 그 결과를 뷰에 전달한다.
  3. 컨트롤러가 알맞은 기능을 처리할 때, 해당 로직을 제공하는 서비스에 그 처리를 위임한다.
  4. DAO를 통해 데이터 베이스에 접근한다.(변경 내용을 DB에 반영)

※ 서비스에 위임하는 예시

ChangePasswordController의 ChangePasswordService.changePassword()을 통한 위임

//서비스 클래스
public class MemberService {
	...
	@Transactional
	public void register(RegisterReqest req) {...} //입력 파라미터를 커맨드 객체로 사용

	@Transactional
	public void changePassword(String email, String oldPwd, String newPwd) {...}
}
//컨트롤러 클래스
@PostMapping
public String submin(
	@ModelAttribute("command") ChangePwdCommand pwdCmd,
	Errors errors, HttpSession session) {
	new ChangePwdCommandValidator().validate(pwdCmd, errors);
	if (errors.hasErrors()) {
		return "edit/changePwdForm";
	}
	AuthInfo authInfo = (AuthInfo)session.getAttribute("authInfo");
	try {
	//컨트롤러는 로직 실행을 위해 서비스에 위임한다.
	changePasswordService.changePassword(
		authInfo.getEmail(),
		pwdCmd.getCurrentPassword(),
		pwdCmd.getNewPassword());
	return "edit/changedPwd";
} catch (IdPasswordNotMatchingException e) {
	errors.rejectValue("currentPassword" , "notMatching");
	return "edit/changePwdForm";
	}
}

컨트롤러의 주요 역할

  • 클라이언트가 요구한 기능 실행
  • 응답 결과를 생성하는데 필요한 모델 생성
  • 응답 결과를 생성할 뷰 선택

 

2. 서비스의 구현

서비스가 구현하는 비밀번호 변경 기능의 로직

  • DB에서 비밀번호를 변경할 회원의 데이터를 구한다.
  • 존재하지 않으면 익셉션을 발생시킨다.
  • 회원 데이터의 비밀번호를 변경한다.
  • 변경 내역을 DB에 반영한다.

 

서비스 클래스 작성

  • MemberRegisterService : 회원 가입 기능 제공
    • 필요한 데이터를 전달받기 위해 별도 타입안 커맨드 객체로 해당 타입을 사용할 수 있다.
  • ChangePasswordService : 비밀번호 변경 기능 제공
//서비스 클래스
public class MemberService {
	...
	//회원가입 기능
	@Transactional
	public void register(RegisterReqest req) {...} //입력 파라미터를 커맨드 객체로 사용

	//비밀번호 변경 기능
	@Transactional
	public void changePassword(String email, String oldPwd, String newPwd) {...}
}

위의 메서드를 트랜잭션 범위에서 실행한다.

@Transactional
public void changePassword(String email, String oldPwd, String newPwd) {
	Member member = memberDao.selectByEmail(email); //email이 같은 member 가져오기
	if(member == null) //없다면
		throw new MemberNotFoundException(); //에러 발생
	
	member.changePassword(oldPwd, newPwd); //있다면 비밀번호 변경
	
	memberDao.update(member); //DB 업데이트
}

 

커맨드 클래스

  • 사용 이유 : 스프링 MVC가 제공하는 폼 값 바인딩과 검증, 스프링 폼 태그의 연동 기능을 사용하기 위해 작성한다.
  • 리턴 값을 이용한 정상 결과
  • 리턴 값을 이용한 비정상 결과
//AuthService 클래스

@RequestMapping(method = RequestMethod.POST)
public String submit(
	LoginCommand loginCommand, Errors errors, HttpSession session,
	HttpServletResponse response) {
...
	try {
		AuthInfo authInfo = authService.authenticate( //인증과정
		loginCommand.getEmail(),
		loginCommand.getPassword());

		session.setAttribute("authInfo", authInfo);
		...
		return "login/loginSuccess"; //정상결과
	} catch (WrongIdPasswordException e) {
		errors.reject("idPasswordNotMatching");
		return "login/loginForm"; //비정상 결과
	}
}

 

3. 컨트롤러에서의 DAO 접근

  • 회원 데이터 조회를 위한 서비스 메서드
  • 사실상 DAO를 직접 호출하는 것과 동일하다.(DAO에 직접 접근)
  • memberDao.selectById(id);
//서비스 클래스
public class MemberService {
	...
	public Member getMember(Long id) {
		return memberDao.selectById(id);
	}
}
//컨트롤러 클래스
@RequestMapping("/member/detail/{id}")
public String detail(@PathVariable("id") Long id, Model model) {
	//사실상 DAO를 직접 호출하는 것과 동일(memberDao.selectById(id))
	Member member = memberService.getMember(id);
	if(member == null) {
		return "member/notFound";
	}
	model.addAttribute("member", member);
	return "member/memberDetail";
}

 

4. 패키지 구성

  • 패키지 구성은 사실 정답이 없다.
  • Service - Dao - Model 과 같은 세부 패키지로 구분한다.

Q&A - 빈칸 채우기

1. 웹 어플리케이션의 구성 요소는 (프론트 서블릿), (컨트롤러), (서비스), (DAO) 이다.

2. 컨트롤러는 (클라이언트)가 요구한 기능을 실행하고, 응답 결과를 생성하는데 필요한 (모델)을 생성하고, 응답 결과를 생성한 ()를 선택한다.

3. 컨트롤러는 해당 로직을 제공하는 (서비스)에 처리를 위임한다.

4. (서비스)는 핵심이 되는 기능의 로직을 제공한다.

5. 필요한 데이터를 전달받기 위해 별도 타입을 만들면 스프링 MVC의 (커맨드 객체)로 해당 타입을 사용할 수 있어서 편하다.

6. 커맨드 클래스를 작성하는 이유는 스프링 MVC가 제공하는 폼 값 (바인딩)과 (검증), (스프링 폼 태그)와 연동 기능을 사용하기 위함이다.

7. 패키지 구성은 대체로 (Service) - (Dao) - (Model)로 구성된다.

 

Q&A - 주관식 문제

1. DAO에 직접 접근하도록 메서드를 수정해 보세요.

public class MemberService {
	...
	public Member getMember(Long id) {
		return memberDao.selectById(id);
	}
}
@RequestMapping("/member/detail/{id}")
public String detail(@PathVariable("id") Long id, Model model) {
	//이 부분을 수정하시오!!!!!!!!!!!!
	Member member = memberService.getMember(id);
    
	if(member == null) {
		return "member/notFound";
	}
	model.addAttribute("member", member);
	return "member/memberDetail";
}

답: Member member =  memberDao.selectById(id);

 

2. 컨트롤러가 서비스에 위임하도록 작성하시오.

//서비스 클래스
public class MemberService {
	...
	@Transactional
	public void regist(RegisterReqest req) {...}
}
//컨트롤러 클래스
@Autowired
private MemberService memberRegisterService;

@PostMapping("/register/step3")
public String handleStep3(RegisterRequest regReq, Errors errors) {
	...
	//이부분 작성
	...
}

답: memberRegisterService.regist(regReq);

728x90

관련글 더보기