[Spring] 스프링 서비스 & DAO 객체 구현(Spring Service & DAO Implementation)

| 스프링 서비스 & DAO 객체 구현(Spring Service & DAO Implementation)


기본적인 서비스와 DAO 객체를 구현한 스프링 프로젝트를 구축해보고자 한다. 아파치 톰캣(Apache Tomcat) 상에서 실행되며 이클립스(Eclipse) IDE를 사용하여 빠르게 프로젝트를 실행해 보거나 디버깅할 수 있다.


| 프로젝트 구조(Project Structure)


이클립스 상에서 Project Explorer에 나타낸 프로젝트 구조는 다음과 같다. 기본적인 서비스와 DAO 객체를 구현한 예제이다. 





| 스프링 UTF-8 인코딩 필터 설정(Spring UTF-8 Encoding Filter Configuration)


스프링에서는 UTF-8 인코딩을 따로 설정해주지 않으면 한글이 깨지는 현상이 발생한다. web.xml 파일에 아래의 설정 정보를 붙여넣는다.


web.xml

<filter>
	<filter-name>encodingFilter</filter-name>
	<filter-class>
		org.springframework.web.filter.CharacterEncodingFilter
	</filter-class>
	<init-param>
		<param-name>encoding</param-name>
		<param-value>UTF-8</param-value>
	</init-param>
	<init-param>
		<param-name>forceEncoding</param-name>
		<param-value>true</param-value>
	</init-param>
</filter>

<filter-mapping>
	<filter-name>encodingFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>


| HTML 파일 만들기


src - main - webapp - resources - html 디렉터리에 정적인 HTML 파일을 생성한다. HTML 파일들은 다음과 같다.


login.html

<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<h1>Login</h1>
	<form action="/mvc/memLogin" method="post">
		ID : <input type="text" name="memId"><br>
		PW : <input type="password" name="memPw"><br>
		<input type="submit" value="Login">
 	</form>
 	<a href="/mvc/resources/html/memJoin.html">JOIN</a>
</body>
</html>

memJoin.html

<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<h1>Member Join</h1>
	<form action="/mvc/memJoin" method="post">
		ID : <input type="text" name="memId"><br/>
		PW : <input type="password" name="memPw"><br/>
		MAIL : <input type="text" name="memMail"><br/>
		PHONE : <input type="text" name="memPhone1" size="5"> -
				<input type="text" name="memPhone2" size="5"> - 
				<input type="text" name="memPhone3" size="5"><br/>
		<input type="submit" value="Join">
	</form>		
	<a href="/mvc/resources/html/login.html">LOGIN</a>    
</body>
</html>


| JSP 파일 만들기


src - webapp - WEB-INF - viewsJSP 파일들을 생성한다.


home.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
	<title>Home</title>
</head>
<body>
<body>
	<h1>Main</h1>
	<a href="/mvc/resources/html/memJoin.html">JOIN</a>   
	<a href="/mvc/resources/html/login.html">LOGIN</a>
</body>
</html>

memJoinOK.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<h1>memJoinOK</h1>
	ID : ${memId}<br/>
	PW : ${memPw}<br/>
	Mail : ${memMail}<br/>
	Phone : ${memPhone}<br/>
	<a href="/mvc/resources/html/memJoin.html"> Go Member Join</a> 
</body>
</html>

memLoginOK.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<h1> memLoginOk</h1>
	ID : ${memId}<br/>
	PW : ${memPw}<br/>
	<a href="/mvc/resources/html/index.html"> GO Main</a>
</body>
</html>

${} 기호 안에 있는 것은 JSP로 들어오는 Model 객체의 속성들이며 이 속성값들이 ${}기호 안의 문자열과 치환된다. 치환이 완료된 JSP파일은 HTML문서가 되며 클라이언트에게 보내진다.


| 자바 파일 만들기: 컨트롤러, 서비스, DAO (Java File : Controller, Service, DAO, VO(=DTO))


스프링 프로젝트의 Java Resources 부분에 컨트롤러(Controller), 서비스(Service), DAO(Data Access Object), VO(Value Object)를 추가할 것이다. 각 컴포넌트들이 의미하는 바를 다시 정리하자면


  • 컨트롤러(Controller) : 클라이언트에서 요청이 들어올 때, 해당 요청을 수행할 비즈니스 로직을 제어하는 객체다. 스프링에서는 컨트롤러에서 세부적으로 서비스 레이어(Service Layer)를 만들어 해당 요청사항을 객체 지향적인 방식으로 좀 더 세분화하여 관리한다. 
  • 서비스(Service) : 서비스 레이어(Service Layer)단에서 세분화된 비즈니스로직을 처리하는 객체
  • DAO(Data Access Object) : DB를 사용해 데이터를 조회하거나 조작하는 기능을 전담하도록 만든 객체
  • VO(Value Object) : 각 계층간 데이터 교환을 위한 자바 객체를 의미한다. 이 객체는 데이터를 각 레이어 간에 전달하는 목적을 가지고 있으며 객체의 속성과 getter, setter만 가지고 있다. DTO(Data Transfer Object)로 불릴 수도 있다. 


예로들면 클라이언트가 HTTP로 "컴퓨터 주문"을 요청해왔다고 하자. 이 "컴퓨터 주문"을 처리할 해당 URL이 있을 것이고 해당 URL에 대한 컨트롤러가 작동할 것이다. 그리고 "컴퓨터 주문"도 노트북 혹은 데스크탑, 고수준인지 저수준인지를 체크하는 세부 사항이 있을 것이고 그것을 다루는 계층이 서비스 계층의 서비스 객체다. DAO는 이 요청에 필요한 컴퓨터와 사용자 정보 데이터를 데이터베이스에서 가져오는 역할을 전담한다. 그리고 각 레이어 간에 데이터들은 VO로서 전달된다.


| 컨트롤러(Controller)


com.tutorial.mvc.member.controller 에 각 컨트롤러들을 작성한다.


HomeController.java

@Controller
public class HomeController {
	
	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
	
	/**
	 * Simply selects the home view to render by returning its name.
	 */
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		
		return "home";
	}
}

http://localhost:8090/mvc URL로 클라이언트가 요청을 하게되면 이 컨트롤러는 home.jsp 파일을 찾아 JSP파일이 변환된 HTML파일을 클라이언트에게 넘겨준다.


@Controller 어노테이션은 스프링 프레임워크에서 이 객체가 컨트롤러 역할을 한다는 정보를 담고 있고 스프링 어플리케이션이 실행될 때 컨트롤러로서 해당 객체가 생성된다.


@RequestMappingHandlerAdapter가 컨트롤러의 어떤 메서드를 실행시킬 것인지에 대한 정보를 전달한다. @RequestMapping에는 두 개의 파라미터가 존재한다. value는 URL을 매칭할 때 쓰이는 파라미터이다. method는 어떤 특정 방식(GET, POST)로 요청사항이 올 시 그것에 대해 반응하게 하는 정보를 담는 파라미터다. 


Locale은 어떤 지엽적이고 정치적, 문화적 특징을 나타내는 정보를 담는 객체다. Model은 뷰인 JSP파일에 전달될 속성을 저장하는 객체다. 


MemberController.java

@Controller
public class MemberController {
	
	@Autowired
	MemberService service;
	
	@RequestMapping(value="/memJoin", method=RequestMethod.POST)
	public String memJoin(Model model, HttpServletRequest request) {
		String memId = request.getParameter("memId");
		String memPw = request.getParameter("memPw");
		String memMail = request.getParameter("memMail");
		String memPhone1 = request.getParameter("memPhone1");
		String memPhone2 = request.getParameter("memPhone2");
		String memPhone3 = request.getParameter("memPhone3");
		
		service.memberRegister(memId, memPw, memMail, memPhone1, memPhone2, memPhone3);
		
		model.addAttribute("memId", memId);
		model.addAttribute("memPw", memPw);
		model.addAttribute("memMail", memMail);
		model.addAttribute("memPhone", memPhone1 + "-" + memPhone2 + "-" +  memPhone3);
		
		return "memJoinOK";
	}
	
	@RequestMapping(value="/memLogin", method=RequestMethod.POST)
	public String memLogin(Model model, HttpServletRequest request) {
		String memId = request.getParameter("memId");
		String memPw = request.getParameter("memPw");
		
		Member member = service.memberSearch(memId, memPw);
		
		try {
			model.addAttribute("memId", member.getMemId());
			model.addAttribute("memPw", member.getMemPw());
		} catch (Exception e){
			e.printStackTrace();
		}
		
		return "memLoginOk";
	}
}

Java 코드를 보면 서비스 객체를 참조할 변수 service가 있는 것을 볼 수 있다. @Autowired를 통해 MemberService 타입의 서비스 객체가 자동적으로 주입될 것이다.


memJoin 메서드를 보면 HttpServletRequest 객체가 인자로 들어오는 것을 볼 수 있다. 이것은 클라이언트가 전달한 HTTP 요청의 데이터를 담은 객체라 생각하면 된다. 이 객체의 정보를 얻기 위해서는 getParameter 메서드를 쓰면 된다.


그 다음 코드에서는 HttpServletRequest 객체의 데이터를 얻은 후 그것을 servicememberRegister를 통해서 데이터를 등록하려는 것을 볼 수 있다.


마지막으로 Model 객체인 model에 속성값들을 저장하여 이것을 JSP파일에 전달하는 부분을 살펴볼 수 있다.


memLogin 메서드도 위에서 설명한 것을 토대로 코드를 해석하면 어렵지 않게 파악할 수 있을 것이다.


| 서비스(Service)


com.tutorial.mvc.member.service 에 서비스 인터페이스와 서비스 클래스를 작성한다. 서비스 객체는 스프링 MVC에서는 서비스 인터페이스를 구현한 객체이다. 이런 방식으로 객체를 구현하는 이유는 단순히 if else 문의 단순 중첩문의 유지보수가 어려운 코드를 양산하는 것이 아닌 객체지향적인 방법을 활용하여 유지보수가 편한 코드를 작성하도록 유도하기 위해서이다.


IMemberService.java

public interface IMemberService {
	void memberRegister(String memId, String memPw, String memMail, String memPhone1, String memPhone2, String memPhone3);
	Member memberSearch(String memId, String memPw);
}

MemberService.java

// @Component
// @Repository
@Service
public class MemberService implements IMemberService {
	
	@Autowired
	MemberDao dao;

	@Override
	public void memberRegister(String memId, String memPw, String memMail, String memPhone1, String memPhone2,
			String memPhone3) {
		System.out.println("memberRegister()");
		System.out.println("memId : " + memId);
		System.out.println("memPw : " + memPw);
		System.out.println("memMail : " + memMail);
		System.out.println("memPhone : " + memPhone1 + "-" + memPhone2 + "-" + memPhone3);
		
		dao.memberInsert(memId, memPw, memMail, memPhone1, memPhone2, memPhone3);
	}

	@Override
	public Member memberSearch(String memId, String memPw) {
		
		System.out.println("memberSearch()");
		System.out.println("memId : " + memId);
		System.out.println("memPw : " + memPw);
		
		Member member = dao.memberSelect(memId, memPw);
		
		return member;
	}
}
MemberService 클래스는 IMemberService 인터페이스를 구현한 클래스다. 서비스는 DAO 객체를 참조하는 인스턴스 변수를 가지고 있으며 이것을 통해 데이터베이스에 액세스할 수 있다. 역시 @Autowired를 통해 자동주입이 되는 것을 볼 수 있다.

눈여겨 볼 것은 이 객체가 서비스 객체라는 것을 알리는 어노테이션들이다. @Component, @Repository, @Service 셋 중 하나를 쓰면 되지만 실무에서는 보통 의도가 명확한 @Service 어노테이션을 쓴다.

| DAO(Data Access Object)

DAO는 데이터베이스를 조회, 조작하는 것을 전담하는 객체다. VO(=DTO)를 통해 데이터베이스의 데이터와 매칭되는 객체를 생성한 후 데이터베이스의 데이터를 조회하거나 삽입, 삭제, 갱신할 수 있다.


IMemberDao

public interface IMemberDao {
	void memberInsert(String memId, String memPw, String memMail, String memPhone1, String memPhone2, String memPhone3);
	Member memberSelect(String memId, String memPw);
}

MemberDao

// @Repository
@Component
public class MemberDao implements IMemberDao {

	private HashMap dbMap;
	
	public MemberDao() {
		dbMap = new HashMap();
	}
	
	@Override
	public void memberInsert(String memId, String memPw, String memMail, String memPhone1, String memPhone2,
			String memPhone3) {
		System.out.println("memberInsert()");
		System.out.println("memId : " + memId);
		System.out.println("memPw : " + memPw);
		System.out.println("memMail : " + memMail);
		System.out.println("memPhone : " + memPhone1 + "-" + memPhone2 + "-" + memPhone3);
		
		Member member = new Member();
		member.setMemId(memId);
		member.setMemPw(memPw);
		member.setMemMail(memMail);
		member.setMemPhone1(memPhone1);
		member.setMemPhone2(memPhone2);
		member.setMemPhone3(memPhone3);
		
		dbMap.put(memId, member);
		
		Set keys = dbMap.keySet();
		Iterator iterator = keys.iterator();
		
		while(iterator.hasNext()) {
			String key = iterator.next();
			Member mem = dbMap.get(key);
			System.out.print("memberId:" + mem.getMemId() + "\t");
			System.out.println("|memberPw:" + mem.getMemPw() + "\t");
			System.out.println("|memberMail:" + mem.getMemMail() + "\t");
			System.out.println("|memberPhone:" + mem.getMemPhone1() + "-" + mem.getMemPhone2() + "-" + mem.getMemPhone3() + "\n");
		}
	}

	@Override
	public Member memberSelect(String memId, String memPw) {
		Member member = dbMap.get(memId);
		return member;
	}
}

DAO도 객체지향적인 코드 작성을 유도하기 위해 인터페이스를 구현한 클래스를 구현한다. 원래대로라면 데이터베이스와 상호작용하는 코드를 작성해야하지만 이번에는 데이터베이스를 HashMap으로 대체한 코드를 작성하였다. 


MemberDao의 메서드들을 보면 VOMember 객체를 이용하여 데이터를 데이터베이스를 대체한 HashMap과 상호작용하는 모습을 볼 수 있다. 또한 검색한 데이터를 Member 객체로서 서비스 레이어에 반환하는 모습을 memberSelect 메서드를 통해 볼 수 있다.


| VO(Value Object)


VO는 계층간 데이터 교환을 하기 위한 객체다. 이 객체는 데이터를 표현하기 위한 멤버 변수와 getter, setter밖에 존재하지 않는 단순한 객체다.


Member.java

public class Member {
	private String memId;
	private String memPw;
	private String memMail;
	private String memPhone1;
	private String memPhone2;
	private String memPhone3;
	
	public String getMemId() {
		return memId;
	}
	public void setMemId(String memId) {
		this.memId = memId;
	}
	public String getMemPw() {
		return memPw;
	}
	public void setMemPw(String memPw) {
		this.memPw = memPw;
	}
	public String getMemMail() {
		return memMail;
	}
	public void setMemMail(String memMail) {
		this.memMail = memMail;
	}
	public String getMemPhone1() {
		return memPhone1;
	}
	public void setMemPhone1(String memPhone1) {
		this.memPhone1 = memPhone1;
	}
	public String getMemPhone2() {
		return memPhone2;
	}
	public void setMemPhone2(String memPhone2) {
		this.memPhone2 = memPhone2;
	}
	public String getMemPhone3() {
		return memPhone3;
	}
	public void setMemPhone3(String memPhone3) {
		this.memPhone3 = memPhone3;
	}
}


| 실행화면


이클립스 IDE에서 프로젝트를 Run on Server로서 실행하게 되면 톰캣이 실행되고 스프링 어플리케이션이 구동된다.






참고자료 : https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC_renew/

이 글을 공유하기

댓글(0)

Designed by JB FACTORY