728x90
반응형
본 게시글은 스프링 5 프로그래밍 입문 책을 복습하는 용도로 게시되었음을 알려드립니다.
- 한 클래스가 다른 클래스의 메서드를 실행할 때 의존이라고 표현한다.
- 한 클래스가 다른 클래스의 메서드를 실행 할 때 의존이라고 표현한다.
💡 회원 데이터 관련 클래스
- Member
- WrongIdPasswordException
- MemberDao
💡회원 가입 처리 관련 클래스
- DuplicateMemberException
- RegisterRequest
- MemberRegisterService
💡 암호 변경 관련 클래스
- MemberNotFoundException
- ChangePasswordService
🧑🏻 회원 데이터 관련 클래스
[패키지]/[클래스]
spring/Member.java
package spring;
import java.time.LocalDateTime;
public class Member {
private Long id;
private String email;
private String password;
private String name;
private LocalDateTime registerDateTime;
public Member(String email, String password, String name, LocalDateTime regDateTime) {
this.email = email;
this.password = password;
this.name = name;
this.registerDateTime = regDateTime;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
public String getName() {
return name;
}
public LocalDateTime getRegisterDateTime() {
return registerDateTime;
}
public void changePassword(String oldPassword, String newPassword) {
//기존 비밀번호가 일치하지 않으면 예외처리..
if(!password.equals(oldPassword)) throw new WrongIdPasswordException();
this.password = newPassword; //새로운 비밀번호 대입.
}
}
- 기존 비밀번호가 일치하지 않으면 예외처리
- oldPassword 와 newPassword가 다르면 WrongIdPasswordException 발생
- spring/WrongIdPasswordException.java
package spring;
public class WrongIdPasswordException extends RuntimeException{
/* ''' '''*/
}
spring/MemberDao.java
package spring;
import java.util.HashMap;
import java.util.Map;
public class MemberDao {
private static long nextId = 0;
private Map<String, Member> map = new HashMap<>();
public Member selectByEmail(String email) {
return map.get(email);
}
public void insert(Member member){
member.setId(++nextId);
map.put(member.getEmail(), member);
}
public void update(Member member) {
map.put(member.getEmail(), member);
}
}
- Map 자료구조로 데이터 조회, 삽입, 수정
📺 회원 가입 처리 관련 클래스
spring/DuplicateMemberException.java
package spring;
public class DuplicateMemberException extends RuntimeException{
public DuplicateMemberException(String message) {
super(message);
}
}
- 중복회원과 관련한 Exception
- 동일한 이메일을 갖고 있는 회원이 이미 존재할 때 MemberRegisterService가 발생시키는 익셉션
spring/RegisterRequest.java
package spring;
public class RegisterRequest {
private String email;
private String password;
private String confirmPassword;
private String name;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isPasswordEqualToConfirmPassword() {
return password.equals(confirmPassword);
}
}
- 회원등록 기능을 구현하기 위한 정 보드를 담은 클래스
/spring/MemberRegisterService.java
package spring;
import java.time.LocalDateTime;
public class MemberRegisterService {
private MemberDao memberDao;
public MemberRegisterService(MemberDao memberDao) {
this.memberDao = memberDao;
}
public Long regist(RegisterRequest req) {
Member member = memberDao.selectByEmail(req.getEmail());
if(member != null) {
throw new DuplicateMemberException("dup email " + req.getEmail());
}
Member newMember = new Member(
req.getEmail(), req.getPassword(), req.getName(), LocalDateTime.now());
memberDao.insert(newMember);
return newMember.getId();
}
}
- 같은 이메일을 갖는 회원이 존재하지 않으면 Member 객체를 생성한 뒤, memberDao.insert() 메서드를 통해 저장한다.
🔒 암호 변경 관련 클래스
spring/ChangePasswordService.java
package spring;
public class ChangePasswordService {
private MemberDao memberDao;
public void chagnePassword(String email, String oldPwd, String newPwd) {
Member member = memberDao.selectByEmail(email);
if(member == null) throw new MemberNotFoundException();
member.changePassword(oldPwd, newPwd);
memberDao.update(member);
}
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
}
- 데이터를 찾기위해 email를 활용한다.
- Member 객체를 생성하여 키값 email을 통해, 해당 Member객체를 조회한다.
- 만약, 찾지못하면 (null), MemberNotFoundException를 발생시킨다.
- 찾았다면, member.chagePassword()메서드를 통해 oldPwd가 현재 비밀번호와 일치하다면, newPwd를 Member클래스의 password 변수에 대입한다.
- memberDao.update(Member) 메서드를 통해 Map 자료구조에 put 한다.
- key : getEmail() / value : member
🧰 객체 조립
- 의존 객체를 주입해주는 클래스를 따로 작성한다.
- 의존 객체를 주입한다는 것은 서로 다른 두 객체를 조립한다고 생각할 수 있다
- 이를 클래스 조립기라고도 표현한다.
/assembler/Assembler.java
package assembler;
import spring.ChangePasswordService;
import spring.MemberDao;
import spring.MemberRegisterService;
public class Assembler {
private MemberDao memberDao;
private MemberRegisterService regSvc;
private ChangePasswordService pwdSvc;
public Assembler() {
// TODO Auto-generated constructor stub
memberDao = new MemberDao(); //의존 객체를 변경하려면 조립기의 코드만 수정하면된다.
regSvc = new MemberRegisterService(memberDao);
pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao);
}
public MemberDao getMemberDao() {
return memberDao;
}
public ChangePasswordService getChangePasswordService() {
return pwdSvc;
}
public MemberRegisterService getMemberRegisterService() {
return regSvc;
}
}
- Assembler 생성자를 통해 각 객체들을 생성한다.
- MemberRegisterService와 ChangePasswordService 객체에 대한 의존 주입
- MemberRegisterSerivce는 생성자를 통해 MemberDao객체를 주입받는다.
- ChangePasswordService는 세터(setMemberDao)를 통해 주입받는다.
- 의존 객체를 변경하려면 조립기의 코드만 수정하면 된다.!! CashedMemberDao주입
public Assembler() {
// TODO Auto-generated constructor stub
memberDao = new CashedMemberDao(); //의존 객체를 변경하려면 조립기의 코드만 수정하면된다.
regSvc = new MemberRegisterService(memberDao);
pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao);
}
🔧 조립기를 사용한 Main 클래스
package main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import assembler.Assembler;
import spring.ChangePasswordService;
import spring.DuplicateMemberException;
import spring.MemberNotFoundException;
import spring.MemberRegisterService;
import spring.RegisterRequest;
import spring.WrongIdPasswordException;
public class Main {
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
//콘솔에서 입력받기 위해 System.in을 이용해서 BufferReader를 생성
BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
while(true) {
System.out.println("명령어를 입력하세요.");
//BufferedReader#readLine() 메서드를 이용해 콘솔에서 한 줄을 입력받는다.
String command = reader.readLine();
if(command.equalsIgnoreCase("exit")) {
//입력한 문자열이 "exit" > 프로그램 종료
System.out.println("종료합니다.");
break;
}
if(command.startsWith("new ")) {
//입력한 문자열이 "new "로 시작하면 processNewCommmand()메서드를 실행한다.
processNewCommand(command.split(" "));
continue;
}
else if(command.startsWith("change ")) {
//입력한 문자열이 "change "로 시작하면 processChangeCommand()메서드를 실행한다.
processChangeCommand(command.split(" "));
continue;
}
//명령어를 잘못입력한 경우 도움말을 출력해주는 pringHelp()메서드를 실행한다.
printHelp();
}
}
private static Assembler assembler = new Assembler();
private static void processNewCommand(String[] arg) {
if(arg.length != 5) {
printHelp();
return;
}
//MemberRegisterService 객체를 Assembler를 통해 생성
MemberRegisterService regSvc = assembler.getMemberRegisterService();
RegisterRequest req = new RegisterRequest();
req.setEmail(arg[1]);
req.setName(arg[2]);
req.setPassword(arg[3]);
req.setConfirmPassword(arg[4]);
if(!req.isPasswordEqualToConfirmPassword()) {
System.out.println("암호와 확인이 일치하지 않습니다. \n");
}
try {
regSvc.regist(req);
System.out.println("등록했습니다. \n");
} catch (DuplicateMemberException e) {
// TODO: handle exception
System.out.println("이미 존재하는 이메일입니다. \n");
}
}
private static void processChangeCommand(String[] arg) {
if(arg.length != 4) {
printHelp();
return;
}
//ChangePasswordService 객체를 Assembler를 통해 생성
ChangePasswordService changePwdSvc =
assembler.getChangePasswordService();
try {
changePwdSvc.chagnePassword(arg[1], arg[2], arg[3]);
System.out.println("암호를 변경했습니다. \n");
} catch (MemberNotFoundException e) {
System.out.println("존재하지 않는 이메일입니다. \n");
} catch (WrongIdPasswordException e) {
System.out.println("암호가 일치하지 않습니다. \n");
}
}
private static void printHelp() {
System.out.println();
System.out.println("잘못된 명령어입니다. 아래 명령어 사용법을 확인하세요.");
System.out.println("명령어 사용법:");
System.out.println("new 이메일 이름 암호 암호확인");
System.out.println("change 이메일 현재비번 변경비번");
System.out.println();
}
}
📺 Main 클래스 결과
🌷 스프링의 DI 설정
config/Appctx.java
package config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import spring.ChangePasswordService;
import spring.MemberDao;
import spring.MemberRegisterService;
@Configuration // 스프링 설정 클래스 의미, 이 애노테이션을 붙여야 스프링 설정 클래스로 사용가능
public class AppCtx {
@Bean //memberDao()메서드를 통해 생성한 빈 객체는 "memberDao"라는 이름으로 스프링에 등록된다.
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberRegisterService memberRegSvc() {
// MemberRegisterService 생성자를 호출할 때 memberDao()메서드를 호출
// 즉, memberDao()가 생성한 객체를 MemberRegisterService 생성자를 통해 주입한다.
return new MemberRegisterService(memberDao());
}
@Bean
public ChangePasswordService changePwdSvc() {
//ChangePasswordService 타입의 빈을 설정한다.
//이 메서드는 세터(setMemberDao()메서드)를 이용해서 의존 객체를 주입한다.
ChangePasswordService pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao());
return pwdSvc;
}
}
- 설정 클래스를 만들었다고 해서 끝난 것은 아니다.
- 객체를 생성하고 의존 객체를 주입하는 것은 스프링 컨테이너이므로 설정 클래스를 이용해서 컨테이너를 생성해야 한다.
ApplicationContext ctx = new AnnotationConfigApplcationContext(AppCtx.class);
- 컨테이너를 생성하면 getBean() 메서드를 이용해서 사용자 객체를 구할 수 있다.
MemberRegisterService regSvc = ctx.getbean("memberRegSvc", MemberRegisterService.class);
- 위 코드는 스프링 컨테이너(ctx)로 부터 이름이 "memberRegSvc"라는 빈 객체를 구한다.
- meberRegSvc()라는 @Bean 메서드를 설정했기 때문이다.
- 해당 메서드는 MemberRegisterService 객체에 생성자를 통해 memberDao를 주입한다.
- 따라서, MemberRegisterService 객체는 내부에서 memberDao 빈 객체를 사용한다.
🏋🏻 Spring Main 클래스
package main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import config.AppCtx;
import spring.ChangePasswordService;
import spring.DuplicateMemberException;
import spring.MemberNotFoundException;
import spring.MemberRegisterService;
import spring.RegisterRequest;
import spring.WrongIdPasswordException;
public class MainForSpring {
//Spring 컨테이너를 사용하는 MainForSpring실행
private static ApplicationContext ctx = null;
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
ctx = new AnnotationConfigApplicationContext(AppCtx.class);
BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
while(true) {
System.out.println("명령어를 입력하세요.");
//BufferedReader#readLine() 메서드를 이용해 콘솔에서 한 줄을 입력받는다.
String command = reader.readLine();
if(command.equalsIgnoreCase("exit")) {
//입력한 문자열이 "exit" > 프로그램 종료
System.out.println("종료합니다.");
break;
}
if(command.startsWith("new ")) {
//입력한 문자열이 "new "로 시작하면 processNewCommmand()메서드를 실행한다.
processNewCommand(command.split(" "));
continue;
}
else if(command.startsWith("change ")) {
//입력한 문자열이 "change "로 시작하면 processChangeCommand()메서드를 실행한다.
processChangeCommand(command.split(" "));
continue;
}
//명령어를 잘못입력한 경우 도움말을 출력해주는 pringHelp()메서드를 실행한다.
printHelp();
}
}
private static void printHelp() {
System.out.println();
System.out.println("잘못된 명령어입니다. 아래 명령어 사용법을 확인하세요.");
System.out.println("명령어 사용법:");
System.out.println("new 이메일 이름 암호 암호확인");
System.out.println("change 이메일 현재비번 변경비번");
System.out.println();
}
private static void processChangeCommand(String[] arg) {
if(arg.length != 4) {
printHelp();
return;
}
//getBean메소드로 chagePwdSvc 빈 객체 호출
ChangePasswordService changePwdSvc =
ctx.getBean("changePwdSvc", ChangePasswordService.class);
try {
changePwdSvc.chagnePassword(arg[1], arg[2], arg[3]);
System.out.println("암호를 변경했습니다. \n");
} catch (MemberNotFoundException e) {
System.out.println("존재하지 않는 이메일입니다. \n");
} catch (WrongIdPasswordException e) {
System.out.println("암호가 일치하지 않습니다. \n");
}
}
private static void processNewCommand(String[] arg) {
if(arg.length != 5) {
printHelp();
return;
}
//getBean메소드로 memberRegSvc 빈 객체 호출
MemberRegisterService regSvc = ctx.getBean("memberRegSvc", MemberRegisterService.class);
RegisterRequest req = new RegisterRequest();
req.setEmail(arg[1]);
req.setName(arg[2]);
req.setPassword(arg[3]);
req.setConfirmPassword(arg[4]);
if(!req.isPasswordEqualToConfirmPassword()) {
System.out.println("암호와 확인이 일치하지 않습니다. \n");
}
try {
regSvc.regist(req);
System.out.println("등록했습니다. \n");
} catch (DuplicateMemberException e) {
// TODO: handle exception
System.out.println("이미 존재하는 이메일입니다. \n");
}
}
}
- 조립기 Assembler 클래스와 차이
- ApplicationContext 생성을 통해 스프링 컨테이너를 사용
- getBean 메서드를 통해 빈 객체 호출
💻 Spring main 클래스 결과
🔨 에러 대응
MainForSpring 클래스를 실행할 때 몇 가지 에러가 발생할 수 있다. 주로 발생하는 에러는 다음과 같다.
- 빈 설정 메서드에 @Bean을 붙이지 않은 경우
- NoSuchBeanDefinitionException 발생
- @Bean 설정 메서드의 이름과 getBean()메서드를 전달한 이름이 다른 경우
- NoSuchBeanDefinitionException 발생
728x90
반응형
'Spring' 카테고리의 다른 글
[Spring] 스프링 컨테이너 생성 (0) | 2023.02.08 |
---|---|
[Spring] Spring의 핵심 및 목적 (0) | 2023.02.07 |
[Spring] 객체지향 프로그래밍과 5원칙 (0) | 2023.02.07 |
[Spring] Spring MVC 란? (1) | 2023.02.04 |
Maven - pom.xml란 ? (0) | 2022.12.20 |