Chapter 4. Service 구현(회원관리 CRUD 만들기 STEP2)

김승현·2021년 10월 24일
0

Service


  • Spring MVC 구조에서 사용되는 객체

  • 기존 MVC 구조는 View → Controller → Model(DAO) 로 동작하는 구조였다.

  • STEP1에서 DAO를 생각해보면 DAO 안에서는 아래와 같은 행동들을 수행한다.

    • 드라이버 등록
    • DBMS 연결
    • Statement 객체 생성
    • SQL 구문 전송 및 결과 리턴
    • 결과 처리
  • 드라이버 등록부터 DBMS 연결 등 많은 수행을 DAO 에서 처리하다 보니 DAO 코드가 자체가 길어진다.

  • 또한, DAO는 하나의 처리당 하나의 DAO를 처리 해야 하는데, DB의 Query 동작이 2개가 동작해야 하는경우 코드를 2번 작동하게 된다.

  • ex) 회원 삭제시 삭제 회원 테이블에 정보 기록 + 회원테이블에서 삭제 여부 Y로 변경

  • 즉, 이러한 구조를 처리하기 위해 사용하는 Class를 Service Class라 한다.

  • Service Class를 구현하게 되면 각자의 역할은 아래와 같다.

    • View Class : 사용자(USER)에게 메뉴 및 화면을 보여주는 Class
    • Controller Class : 사용자(USER)의 요청에 따라 데이터를 받아주거나 필터링 및 어떤 Service를 호출한 것인지를 제어하는 Class
    • Service Class : 드라이버 등록 및 DBMS 연동 그리고 어떤 DAO를 호출할 것인지, 결과에 따라 commit과 rollback 작업
    • DAO Class : 요청에 따른 SQL 처리 및 결과 리턴

  • MVC패턴

TestRun Class (STEP1과 동일)


  • TestRun Class는 View 를 호출하여 시작하기 위한 Class (실행용)
package com.test.run;

import com.test.member.view.MemberView;

public class TestMain {

	public static void main(String[] args) {
		new MemberView().start();
	}
}

VO Class (STEP1과 동일)


  • VO 클래스는 사용자가 입력한 회원정보 및 DB에서 회원 정보를 가져오기 위한 DTO 역할도 수행하는 Class
  • Setter / Getter 메소드를 가지고 있으며, 상황에 따른 매개변수 있는 생성자를 만들어서 사용
package com.test.member.model.vo;

import java.sql.Date;

public class Member {

	private int memberNo;
	private String memberId;
	private String memberPwd;
	private String memberName;
	private char gender;
	private int age;
	private String email;
	private String phone;
	private String address;
	private String hobby;
	private Date enrollDate;
	private char withdrawYN;

	public Member() {}
	
	public Member(String memberId, String memberPwd, String memberName, char gender, int age, String email,
			String phone, String address, String hobby) {
		super();
		this.memberId = memberId;
		this.memberPwd = memberPwd;
		this.memberName = memberName;
		this.gender = gender;
		this.age = age;
		this.email = email;
		this.phone = phone;
		this.address = address;
		this.hobby = hobby;
	}

	public int getMemberNo() {
		return memberNo;
	}

	public void setMemberNo(int memberNo) {
		this.memberNo = memberNo;
	}

	public String getMemberId() {
		return memberId;
	}

	public void setMemberId(String memberId) {
		this.memberId = memberId;
	}

	public String getMemberPwd() {
		return memberPwd;
	}

	public void setMemberPwd(String memberPwd) {
		this.memberPwd = memberPwd;
	}

	public String getMemberName() {
		return memberName;
	}

	public void setMemberName(String memberName) {
		this.memberName = memberName;
	}

	public char getGender() {
		return gender;
	}

	public void setGender(char gender) {
		this.gender = gender;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getHobby() {
		return hobby;
	}

	public void setHobby(String hobby) {
		this.hobby = hobby;
	}

	public Date getEnrollDate() {
		return enrollDate;
	}

	public void setEnrollDate(Date enrollDate) {
		this.enrollDate = enrollDate;
	}

	public char getWithdrawYN() {
		return withdrawYN;
	}

	public void setWithdrawYN(char withdrawYN) {
		this.withdrawYN = withdrawYN;
	}

	@Override
	public String toString() {
		return memberNo + "/" + memberId + "/" + memberPwd + "/" + memberName + "/" + gender + "/" + age + "/" + email
				+ "/" + phone + "/" + address + "/" + hobby + "/" + enrollDate + "/" + withdrawYN;
	}

}

View Class (STEP1과 동일)


  • View 클래스는 사용자에게 보여지는 화면

  • Web 으로 표현하자면 Front-End 파트가 View Class 가 하는 역할

  • 사용자는 View 에서 보여주는 메뉴를 가지고 선택할 수 있게 되고, 선택된것에 따라 View는 Controller에게 요청 함

  • 현재 회원관리 프로그램에서는 다음과 같은 메뉴를 가지고 있다.

    • 회원 전체 조회 (SELECT)
    • ID로 조회 (SELECT)
    • 이름으로 조회 (SELECT)
    • 정보 추가 (INSERT)
    • 정보 수정 (UPDATE)
    • 정보 삭제 (UPDATE)
      • 삭제라고 해서 무조건 DELETE는 아니다.
        (회원 정보는 함부로 삭제 하지 않는다.)
package com.test.member.view;

import java.util.ArrayList;
import java.util.Scanner;

import com.test.member.controller.MemberController;
import com.test.member.model.vo.Member;

public class MemberView {

	private Scanner sc = new Scanner(System.in);
	private MemberController mCon = new MemberController();

	// 가장 먼저 시작하는 메소드
	public void start() {

		while (true) {
			System.out.println("---------- 회원 관리 프로그램 ver 1.0 ----------");
			System.out.println("1. 전체 회원 정보 조회");
			System.out.println("2. ID로 회원 조회");
			System.out.println("3. 이름으로 회원 조회");
			System.out.println("4. 회원 정보 추가");
			System.out.println("5. 회원 정보 수정");
			System.out.println("6. 회원 정보 삭제");
			System.out.println("0. 프로그램 종료");
			System.out.print("선택 : ");
			int select = sc.nextInt();

			if (select == 0) {
				System.out.println("프로그램을 종료합니다. 사용해주셔서 감사합니다. (--) (_ _) 꾸벅");
				return;
			}

			switch (select) {
			case 1:
				selectAll();
				break;
			case 2:
				selectOneId();
				break;
			case 3:
				selectName();
				break;
			case 4:
				insertMember();
				break;
			case 5:
				updateMember();
				break;
			case 6:
				deleteMember();
				break;

			}
		}
	}

	public void selectAll() {

		ArrayList<Member> list = mCon.selectAll();

		System.out.println("============= 회원정보 출력 =============");

		for (Member m : list) {
			System.out.println(m);
		}
	}

	public void selectOneId() {
		// 사용자에게 찾으려고하는 ID 를 입력하라고 해야함
		System.out.print("검색하려는 회원ID 입력 : ");
		String memberId = sc.next();

		Member m = mCon.selectOneId(memberId);

		if (m != null) {
			System.out.println("------------- " + memberId + " 회원정보-------------");
			System.out.println("이름 : " + m.getMemberName());
			System.out.println("나이 : " + m.getAge());
			System.out.println("주소 : " + m.getAddress());
			System.out.println("성별 : " + m.getGender());
			System.out.println("폰번호 : " + m.getPhone());
			System.out.println("이메일 : " + m.getEmail());
			System.out.println("취미 : " + m.getHobby());
			System.out.println("가입일 : " + m.getEnrollDate());
		} else {
			System.out.println(memberId + "를(을) 가진 회원을 검색하지 못하였습니다.");
		}

	}

	public void selectName() {
		System.out.print("검색하려는 회원 이름 입력 : ");
		String memberName = sc.next();

		ArrayList<Member> list = mCon.selectName(memberName);

		// 결과 2가지 상황
		// 1. 찾았다면 -> 리스트 안에 Member 객체 있다.
		// 2. 못찾았으면 -> 리스트 안에 Member 객체 없다.

		if (!list.isEmpty()) {
			for (Member m : list) {
				System.out.println(m);
			}
		} else {
			System.out.println(memberName + "이라는 이름을 가진 사람을 검색하지 못하였습니다.");
		}
	}

	public void insertMember() {
		System.out.println("----------- 추가될 회원 정보 입력 -----------");
		System.out.print("회원ID : ");
		String memberId = sc.next();

		System.out.print("회원 PWD : ");
		String memberPwd = sc.next();

		System.out.print("회원 이름 : ");
		String memberName = sc.next();

		System.out.print("회원성별(1.남/2.여) : ");
		int gender = sc.nextInt();

		System.out.print("회원 나이 : ");
		int age = sc.nextInt();

		System.out.print("회원 이메일 : ");
		String email = sc.next();

		System.out.print("회원 폰번호 : ");
		String phone = sc.next();

		System.out.print("회원 주소 : ");
		sc.nextLine();
		String address = sc.nextLine();

		System.out.print("회원 취미(여러개인경우,(콤마)로 구분) : ");
		String hobby = sc.next();

		char genderChar;
		if (gender == 1) {
			genderChar = 'M';
		} else {
			genderChar = 'F';
		}

		Member m = new Member(memberId, memberPwd, memberName, genderChar, age, email, phone, address, hobby);

		boolean result = mCon.insertMember(m);

		if (result) {
			System.out.println(m.getMemberName() + "님의 회원정보가 추가 되었습니다.");
		} else {
			System.out.println("회원정보 추가를 실패하였습니다. - 지속적인 문제 발생시 관리자에게 문의해주세요 -");
		}
	}

	public void updateMember() {
		System.out.print("수정하려는 회원의 ID를 입력 : ");
		String memberId = sc.next();

		Member m = mCon.selectOneId(memberId);

		if (m != null) {

			while (true) {
				System.out.println("------------ 검색된 " + m.getMemberName() + " 회원 정보 ------------");
				System.out.println("ID : " + m.getMemberId());
				System.out.println("이름 : " + m.getMemberName());
				System.out.println("성별 : " + m.getGender());
				System.out.println("나이 : " + m.getAge());
				System.out.println("주소 : " + m.getAddress());
				System.out.println("이메일 : " + m.getEmail());
				System.out.println("폰번호 : " + m.getPhone());
				System.out.println("취미 : " + m.getHobby());
				System.out.println("가입일 : " + m.getEnrollDate());
				System.out.println("삭제 여부: " + m.getWithdrawYN());

				System.out.println("-------------------------------------");
				System.out.println("1. 주소 수정");
				System.out.println("2. 이메일 수정");
				System.out.println("3. 폰번호 수정");
				System.out.println("4. 취미 수정");
				System.out.println("0. 수정 취소");
				System.out.print("선택 : ");
				int select = sc.nextInt();

				if (select == 0) {
					break;
				}
				switch (select) {
				case 1:
					System.out.print("수정될 주소 입력 : ");
					sc.nextLine();
					String address = sc.nextLine();
					m.setAddress(address);
					break;
				case 2:
					System.out.print("수정될 이메일 입력 :");
					String email = sc.next();
					m.setEmail(email);
					break;

				case 3:
					System.out.print("수정될 폰번호 입력 : ");
					String phone = sc.next();
					m.setPhone(phone);
					break;
				case 4:
					System.out.print("수정될 취미 입력 (여러개인 경우 ,(콤마)로 구분) : ");
					String hobby = sc.next();
					m.setHobby(hobby);
					break;
				}
				// 수정된 데이터가 DB에 반영되기 위해서 view에서 controller로 보내주어야한다.
				boolean result = mCon.updateMember(m);

				if (result) {
					System.out.println("회원 정보가 수정되었습니다.");
				} else {
					System.out.println("회원 정보 수정에 실패하였습니다. - 지속적인 문제 발생시 관라자에게 문의해주세요 -");
				}
			}

		} else {
			System.out.println(memberId + "(을)를 가진 회원을 검색하지 못하였습니다.");
		}
	}

	public void deleteMember() {
		System.out.print("삭제하려는 회원의 ID를 입력 : ");
		String memberId = sc.next();
		
		Member m = mCon.selectOneId(memberId);
		
		if(m!=null) {
			System.out.print(m.getMemberId()+"("+m.getMemberName()+")회원을 정말로 삭제하시겠습니까? (Y,N) : ");
			char select = sc.next().toUpperCase().charAt(0);
			
			if(select=='Y') {
				boolean result = mCon.deleteMember(memberId);
				
				if(result) {
					System.out.println(memberId + " 회원을 정상적으로 삭제하였습니다.");
				}else {
					System.out.println("회원삭제를 처리하지 못하였습니다. - 지속적인 문제 발생시 관리자에게 문의해주세요 -");
				}
			}else {
				System.out.println("삭제를 취소하였습니다.");
			}
		}else
			System.out.println(memberId+"(을)를 가진 회원이 없습니다.");
	}
}

Controller Class (호출 대상 변경)


  • 기존 : Controller -> DAO 호출

  • 변경 : Controller-> Service-> DAO 호출

  • JAVA의 코드만으로는 Controller가 필요 없을 수 있음

  • 실제 컨트롤러

    • 넘어오는 데이터 필터링, 인코딩 해주는 등 (한글 인코딩 처리 작업)
      데이터가 DAO로 넘어가기전에 필터링해주는 작업들을 수행
    • DAO에서 DB와의 업무 처리를 빠르게 해주도록 함
  package com.test.member.controller;

import java.util.ArrayList;

import com.test.member.model.service.MemberService;
import com.test.member.model.vo.Member;

public class MemberController {
	
	private MemberService mService = new MemberService();
	
	public ArrayList<Member> selectAll() {

		// cotroller의 역할은 요청을 처리할 수 있는  Service를 연결하는 역할
		ArrayList<Member> list = mService.selectAll();
		return list;
	}
	
	public Member selectOneId(String memberId) {
		Member m = mService.selectOneId(memberId);
		
		return m;
	
	}
	
	public ArrayList<Member> selectName(String memberName) {
		
		ArrayList <Member> list = mService.selectName(memberName);
		
		return list;
	}
	
	
	public boolean insertMember(Member m) {
		
		int resultRow = mService.insertMember(m);
		
		if(resultRow>0) {
			return true;	
		}else {
			return false;
		}
	}
	
	public boolean updateMember(Member m) {
		
		int resultRow = mService.updateMember(m);
		
		if(resultRow>0) {
			return true;
		}else {
			return false;
		}
	}
	
	public boolean deleteMember(String memberId) {
		
		int result = mService.deleteMember(memberId);
		
		if(result >0) {
			return true;
		}else {
			return false;
		}
	}
}


Service Class (추가)


  • 목적: DAO에서 처리했던 코드들의 모듈을 분리하여 코드 간소화
  • 구성
    • 드라이버 등록
    • DBMS 연결
    • DAO 메소드 호출 및 결과 리턴
    • 결과 처리
    • Connection.close();
package com.test.member.model.service;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

// Service의 역할
//1. 드라이버 등록
//2. DBMS 연동
//3. DAO 호출 /  호출할때 DBMS 연결한 Connection 보내주어야 한다.
//4. Connection close 해주는 역할
//5. 필요한 경우에는 commit과 rollback 처리하는 역할

import java.util.ArrayList;

import com.test.member.model.dao.MemberDAO;
import com.test.member.model.vo.Member;

public class MemberService {

	private MemberDAO mDAO = new MemberDAO();

	public ArrayList<Member> selectAll() {

		// Connection 레퍼런스
		Connection conn = null;
		ArrayList<Member> list = null;

		try {
			// 1. 드라이버 등록
			Class.forName("oracle.jdbc.driver.OracleDriver");

			// 2. DBMS 연결
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "member", "1234");

			// 3. DAO 호출/ Connection 객체를 넘겨주면서 호출
			list = mDAO.selectAll(conn);

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return list;

	}

	public Member selectOneId(String memberId) {

		Connection conn = null;
		Member m = null;

		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "member", "1234");
			m = mDAO.selectOneId(memberId, conn);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

		return m;

	}

	public ArrayList<Member> selectName(String memberName) {

		Connection conn = null;
		ArrayList<Member> list = null;

		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "member", "1234");

			list = mDAO.selectName(memberName, conn);

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return list;
	}

	public int insertMember(Member m) {

		Connection conn = null;
		int result = 0;

		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "member", "1234");
			conn.setAutoCommit(false);

			result = mDAO.insertMember(m, conn);

			if (result > 0) {
				conn.commit();
			} else {
				conn.rollback();
			}

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return result;
	}

	public int updateMember(Member m) {

		Connection conn = null;
		int result = 0;

		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "member", "1234");
			conn.setAutoCommit(false);

			result = mDAO.updateMember(m, conn);

			if (result > 0) {
				conn.commit();
			} else {
				conn.rollback();
			}

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}

	public int deleteMember(String memberId) {

		Connection conn = null;
		int result = 0;

		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "member", "1234");
			conn.setAutoCommit(false);

			int deletMemberDelWriteResult = mDAO.deleteMemberDelWrite(memberId, conn);
			int deleteMemberResult = mDAO.deleteMember(memberId, conn);

			if (deletMemberDelWriteResult > 0 && deleteMemberResult > 0) {
				conn.commit();
				result = 1;
			} else {
				conn.rollback();
				result = 0;
			}

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return result;
	}
}

DAO Class (변경)


  • 구성
    • 드라이버등록
    • DBMS 연결
    • SQL 전송 및 결과 리턴
    • 결과 처리
    • Connection.close();
    • close();- Statement, PreparedStatement, Resultset
profile
개발자로 매일 한 걸음

0개의 댓글