package com.gyuone.concert;
import org.springframework.stereotype.Component;
@Component("iuConcert")
public class IUConcert implements Performance {
@Override
public void perform() throws Exception {
// TODO Auto-generated method stub
System.out.println("노래도 잘 불러, 맘씨도 고와, 연기도 잘 해, 대체 못하는게 뭔데????");
throw new Exception();
}
}
Performance.java (인터페이스)
package com.gyuone.concert;
public interface Performance {
public void perform() throws Exception;
}
PianoConcert.java
package com.gyuone.concert;
import org.springframework.stereotype.Component;
@Component("pianoConcert")
public class PianoConcert implements Performance{
@Override
public void perform() throws Exception {
// TODO Auto-generated method stub
System.out.println("피아노 연주");
}
}
config
ConcertConfig.java
package com.gyuone.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import com.gyuone.concert.Audience;
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ComponentScan(basePackages= {"com.gyuone.concert"})
public class ConcertConfig {
@Bean
public Audience audience() {
return new Audience();
}
}
▪ perform 매소드가 실행될 때마다 advice를 하기 위해 사용할 수 있는 pointcut 표현식 execution(* com.adacho.concert.Performance.perform(..)) ▪ execution 지정자를 이용하여 Performance의 perform() 매소드를 선택 ▪ 매소드 명세의 "*" 는 리턴 타입이 무엇이든 된다는 표시 ▪ perform 매소드의 인자 목록에 (..) 는 인자가 무엇이 전달되어도 perform() 매소드를 선택한다는 의미 ▪ Pointcut의 범위를 concert 패키지로만 제한하고자 한다면 within() 지정자를 사용할 수 있음 execution(* com.adacho.concert.Performance.perform(..) && within(com.adacho.concert.*))
ConcertConfig.java
@EnableAspectJAutoProxy
▪ @EnableAspectJAutoProxy(proxyTargetClass = true) @Aspect 애너테이션 된 클래스를 실행시간에 자동으로 프록시 객체를 만들게 함 - Aspect 대상 객체(piano concert)가 인터페이스를 구현한 클래스 이면
- proxy 객체도 해당 인터페이스를 구현하게 작성되므로 getBean() 매서드로
- 객체를 가져오려고 시도할 때 타입이 맞지 않아서 에러가 발생하게 됨,
- 이 때 proxy 객체를 대상 클래스를 직접 상속받아 만들게 하여야 하는데 이 때 사용하는 것이 proxyTargetClass = true 임
package com.gyuone.common;
public class DuplicateMemberException extends RuntimeException{
public DuplicateMemberException(String message) {
super(message);
}
}
MemberNotFoundException.java
package com.gyuone.common;
public class MemberNotFoundException extends RuntimeException{
}
WrongIdPasswordException.java
package com.gyuone.common;
public class WrongIdPasswordException extends RuntimeException{
}
config
AppConfig1.java
package com.gyuone.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.gyuone.dao.MemberDao;
import com.gyuone.service.MemberPrinter;
@Configuration
public class AppConf1 {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter();
}
}
AppConfig2.java
package com.gyuone.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.gyuone.dao.MemberDao;
import com.gyuone.service.ChangePasswordService;
import com.gyuone.service.MemberInfoPrinter;
import com.gyuone.service.MemberListPrinter;
import com.gyuone.service.MemberPrinter;
import com.gyuone.service.MemberRegisterService;
import com.gyuone.service.VersionPrinter;
@Configuration
public class AppConf2 {
@Autowired
private MemberDao memberDao;
@Autowired
private MemberPrinter memberPrinter;
@Bean
public MemberRegisterService memberRegSvc() { // MemberRegisterService의 식별자는 memberRegSvc
return new MemberRegisterService(memberDao);
}
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao);
return pwdSvc;
}
@Bean
public MemberListPrinter listPrinter() {
return new MemberListPrinter(memberDao, memberPrinter);
}
@Bean
public MemberInfoPrinter infoPrinter() {
MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
infoPrinter.setMemberDao(memberDao);
infoPrinter.setPrinter(memberPrinter);
return infoPrinter;
}
@Bean
public VersionPrinter versionPrinter() {
VersionPrinter versionPrinter = new VersionPrinter();
versionPrinter.setMajorVersion(5);
versionPrinter.setMinorVersion(0);
return versionPrinter;
}
}
AppConfig
package com.gyuone.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.gyuone.dao.MemberDao;
import com.gyuone.service.MemberPrinter;
@Configuration
@Import({AppConf2.class})
public class AppConfImport {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter();
}
}
AppCtx.java
package com.gyuone.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import com.gyuone.dao.MemberDao;
import com.gyuone.service.ChangePasswordService;
import com.gyuone.service.MemberInfoPrinter;
import com.gyuone.service.MemberListPrinter;
import com.gyuone.service.MemberPrinter;
import com.gyuone.service.MemberRegisterService;
import com.gyuone.service.MemberSummaryPrinter;
import com.gyuone.service.VersionPrinter;
@Configuration
@ComponentScan(basePackages = {"com.gyuone"},
excludeFilters = @ComponentScan.Filter(type= FilterType.ASSIGNABLE_TYPE, value = {AppConf1.class, AppConf2.class, AppConfImport.class })
) // 지우지 않고 없애버리기 포함시키지 않음
public class AppCtx {
// @Bean
// public MemberDao memberDao() {
// return new MemberDao();
// }
//
// @Bean
// public MemberRegisterService memberRegSvc() { // MemberRegisterService의 식별자는 memberRegSvc
//// return new MemberRegisterService(memberDao());
// return new MemberRegisterService();
// }
//
// @Bean
// public ChangePasswordService changePwdSvc() {
// ChangePasswordService pwdSvc = new ChangePasswordService();
//// pwdSvc.setMemberDao(memberDao()); 필드에다가 Autowired 적용하면 안해도 된다.
// return pwdSvc;
// }
//
// @Bean
// public MemberPrinter memberPrinter() {
// return new MemberPrinter();
// }
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
@Qualifier("summaryPrinter")
public MemberPrinter memberPrinter2() {
return new MemberSummaryPrinter();
}
// @Bean
// public MemberListPrinter listPrinter() {
//// return new MemberListPrinter(memberDao(), memberPrinter());
// return new MemberListPrinter();
// }
// @Bean
// public MemberInfoPrinter infoPrinter() {
// MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
//// infoPrinter.setMemberDao(memberDao());
// infoPrinter.setPrinter(memberPrinter2()); //spring이 알아서 호출 autowired
// return infoPrinter;
// }
@Bean
public VersionPrinter versionPrinter() {
VersionPrinter versionPrinter = new VersionPrinter();
versionPrinter.setMajorVersion(5);
versionPrinter.setMinorVersion(0);
return versionPrinter;
}
}
dao
MemberDao.java
package com.gyuone.dao;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Component;
import com.gyuone.model.Member;
@Component
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);
}
public Collection<Member> selectAll(){
return map.values();
}
}
package com.gyuone.service;
import java.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.gyuone.common.DuplicateMemberException;
import com.gyuone.dao.MemberDao;
import com.gyuone.model.Member;
import com.gyuone.model.RegisterRequest;
@Component
public class MemberRegisterService {
// private MemberDao memberDao = new MemberDao(); // 강한 결합
@Autowired
private MemberDao memberDao;
public MemberRegisterService() { // MemberDao를 받는 기본 생성자
}
public MemberRegisterService(MemberDao memberDao) { // 생성자를 통해서 의존을 주입.. 생성자 의존 주입 = DI
this.memberDao = memberDao;
}
public long register(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();
}
}
MemberSummaryPrinter.java
package com.gyuone.service;
import com.gyuone.model.Member;
public class MemberSummaryPrinter extends MemberPrinter {
@Override
public void print(Member member) {
// TODO Auto-generated method stub
System.out.printf("회원정보 : 이메일=%s, 이름=%s\n", member.getEmail(), member.getName());
}
}
VersionPrinter.java
package com.gyuone.service;
public class VersionPrinter {
private int majorVersion;
private int minorVersion;
public void print() {
System.out.printf("이 프로그램의 버전은 %d.%d입니다.\n\n", majorVersion, minorVersion);
}
public void setMajorVersion(int majorVersion) {
this.majorVersion = majorVersion;
}
public void setMinorVersion(int minorVersion) {
this.minorVersion = minorVersion;
}
}
file new maven project > create a sample project 체크 > Group id : com.gyuone
common
DuplicateMemberException.java
package com.gyuone.common;
public class DuplicateMemberException extends RuntimeException{
public DuplicateMemberException(String message) {
super(message);
}
}
MemberNotFoundException.java
package com.gyuone.common;
public class MemberNotFoundException extends RuntimeException{
}
WrongIdPasswordException.java
package com.gyuone.common;
public class WrongIdPasswordException extends RuntimeException{
}
config
AppConfig1.java
package com.gyuone.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.gyuone.dao.MemberDao;
import com.gyuone.service.MemberPrinter;
@Configuration
public class AppConf1 {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter();
}
}
AppConfig2.java
package com.gyuone.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.gyuone.dao.MemberDao;
import com.gyuone.service.ChangePasswordService;
import com.gyuone.service.MemberInfoPrinter;
import com.gyuone.service.MemberListPrinter;
import com.gyuone.service.MemberPrinter;
import com.gyuone.service.MemberRegisterService;
import com.gyuone.service.VersionPrinter;
@Configuration
public class AppConf2 {
@Autowired
private MemberDao memberDao;
@Autowired
private MemberPrinter memberPrinter;
@Bean
public MemberRegisterService memberRegSvc() { // MemberRegisterService의 식별자는 memberRegSvc
return new MemberRegisterService(memberDao);
}
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao);
return pwdSvc;
}
@Bean
public MemberListPrinter listPrinter() {
return new MemberListPrinter(memberDao, memberPrinter);
}
@Bean
public MemberInfoPrinter infoPrinter() {
MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
infoPrinter.setMemberDao(memberDao);
infoPrinter.setPrinter(memberPrinter);
return infoPrinter;
}
@Bean
public VersionPrinter versionPrinter() {
VersionPrinter versionPrinter = new VersionPrinter();
versionPrinter.setMajorVersion(5);
versionPrinter.setMinorVersion(0);
return versionPrinter;
}
}
AppConfImport.java
package com.gyuone.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.gyuone.dao.MemberDao;
import com.gyuone.service.MemberPrinter;
@Configuration
@Import({AppConf2.class})
public class AppConfImport {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter();
}
}
AppCtx.java
package com.gyuone.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.gyuone.dao.MemberDao;
import com.gyuone.service.ChangePasswordService;
import com.gyuone.service.MemberInfoPrinter;
import com.gyuone.service.MemberListPrinter;
import com.gyuone.service.MemberPrinter;
import com.gyuone.service.MemberRegisterService;
import com.gyuone.service.VersionPrinter;
@Configuration
public class AppCtx {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberRegisterService memberRegSvc() { // MemberRegisterService의 식별자는 memberRegSvc
return new MemberRegisterService(memberDao());
}
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao());
return pwdSvc;
}
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter();
}
@Bean
public MemberListPrinter listPrinter() {
return new MemberListPrinter(memberDao(), memberPrinter());
}
@Bean
public MemberInfoPrinter infoPrinter() {
MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
infoPrinter.setMemberDao(memberDao());
infoPrinter.setPrinter(memberPrinter());
return infoPrinter;
}
@Bean
public VersionPrinter versionPrinter() {
VersionPrinter versionPrinter = new VersionPrinter();
versionPrinter.setMajorVersion(5);
versionPrinter.setMinorVersion(0);
return versionPrinter;
}
}
dao
MemberDao.java
package com.gyuone.dao;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import com.gyuone.model.Member;
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);
}
public Collection<Member> selectAll(){
return map.values();
}
}
package com.gyuone.model;
import java.time.LocalDateTime;
import com.gyuone.common.WrongIdPasswordException;
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 registerDateTime) {
super();
this.email = email;
this.password = password;
this.name = name;
this.registerDateTime = registerDateTime; // 생성자 만들어주기
}
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;
}
}
RegisterRequest.java
package com.gyuone.model;
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);
}
}
service
Assembler.java
package com.gyuone.service;
import com.gyuone.dao.MemberDao;
public class Assembler {
private MemberDao memberDao;
private MemberRegisterService regSvc;
private ChangePasswordService pwdSvc;
public Assembler() {
memberDao = new MemberDao();
regSvc = new MemberRegisterService(memberDao);
pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao);
}
public MemberDao getMemberDao() {
return memberDao;
}
public MemberRegisterService getMemberRegisterService() {
return regSvc;
}
public ChangePasswordService getChangePasswordService() {
return pwdSvc;
}
}
ChangePasswordService.java
package com.gyuone.service;
import com.gyuone.common.MemberNotFoundException;
import com.gyuone.dao.MemberDao;
import com.gyuone.model.Member;
public class ChangePasswordService {
private MemberDao memberDao;
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
public void changePassword(String email, String oldPwd, String newPwd) {
Member member = memberDao.selectByEmail(email);
if(member == null) {
throw new MemberNotFoundException();
}
member.changePassword(oldPwd, newPwd);
memberDao.update(member);
}
}
MemberInfoPrinter.java
package com.gyuone.service;
import com.gyuone.dao.MemberDao;
import com.gyuone.model.Member;
public class MemberInfoPrinter {
private MemberDao memberDao;
private MemberPrinter printer;
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
public void printMemberInfo(String email) {
Member member = memberDao.selectByEmail(email);
if (member == null) {
System.out.println("데이터 없음\n");
return;
}
printer.print(member);
System.out.println();
}
}
MemberListPrinter.java
package com.gyuone.service;
import java.util.Collection;
import com.gyuone.dao.MemberDao;
import com.gyuone.model.Member;
public class MemberListPrinter {
private MemberDao memberDao;
private MemberPrinter printer;
public MemberListPrinter(MemberDao memberDao, MemberPrinter printer) {
this.memberDao = memberDao;
this.printer = printer;
}
public void printMemberInfo(String email) {
Member member = memberDao.selectByEmail(email);
if(member == null) {
System.out.println("데이터 없음\n");
return;
}
printer.print(member);
System.out.println();
}
public void printAll() {
Collection<Member> members = memberDao.selectAll();
members.forEach(m -> printer.print(m));
}
}
MemberPrinter.java
package com.gyuone.service;
import com.gyuone.model.Member;
public class MemberPrinter {
public void print(Member member) {
System.out.printf("회원정보 : 아이디=%d, 이메일=%s, 이름=%s, 등록일=%tF\n", member.getId(),
member.getEmail(), member.getName(), member.getRegisterDateTime());
}
}
MemberRegisterService.java
package com.gyuone.service;
import java.time.LocalDateTime;
import com.gyuone.common.DuplicateMemberException;
import com.gyuone.dao.MemberDao;
import com.gyuone.model.Member;
import com.gyuone.model.RegisterRequest;
public class MemberRegisterService {
// private MemberDao memberDao = new MemberDao(); // 강한 결합
private MemberDao memberDao;
public MemberRegisterService(MemberDao memberDao) { // 생성자를 통해서 의존을 주입.. 생성자 의존 주입 = DI
this.memberDao = memberDao;
}
public long register(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();
}
}
VersionPrinter.java
package com.gyuone.service;
public class VersionPrinter {
private int majorVersion;
private int minorVersion;
public void print() {
System.out.printf("이 프로그램의 버전은 %d.%d입니다.\n\n", majorVersion, minorVersion);
}
public void setMajorVersion(int majorVersion) {
this.majorVersion = majorVersion;
}
public void setMinorVersion(int minorVersion) {
this.minorVersion = minorVersion;
}
}
- 객체를 생성하고 리턴하는 메소드에 @Bean annotation을 설정하면 해당 메소드가 생성한 객체를 스프링이 관리하는 Bean 객체로 등록함
- 해당 메소드의 이름은 생산한 Bean 객체의 식별자로 사용
IOC
Inversion Of Control
제어의 역전
위키백과 : 제어의 반전
역제어는 프로그래머가 작성한 프로그램이 재사용 라이브러리의 흐름 제어를 받게 되는 소프트웨어 디자인 패턴을 말한다. 줄여서 IoC(Inversion of Control)이라고 부른다. 전통적인 프로그래밍에서 흐름은 프로그래머가 작성한 프로그램이 외부 라이브러리의 코드를 호출해 이용한다. 하지만 제어 반전이 적용된 구조에서는 외부 라이브러리의 코드가 프로그래머가 작성한 코드를 호출한다. 설계 목적상 제어 반전의 목적은 다음과 같다
4. bean 이름과 modifier(한정자)
1) 다음의 설정파일 참조
@Bean public MemberPrinter printer() { return new MemberPrinter(); }
@Bean @Qualifier("mprinter") public MemberPrinter printer2() { return new MemberPrinter(); }
@Bean public MemberInfoPrinter2 infoPrinter() { MemberInfoPrinter2 infoPrinter = new MemberInfoPrinter2(); return infoPrinter; }
• printer() 에서 반환하는 bean의 modifier는 bean 이름인 "printer" • printer2() 에서 반환하는 bean의 modifier는 "mprinter" • @Autowired 경우도 @Qualifier 가 없으면 필드나 인자의 이름을 modifier로 사용 • 다음의 경우에 printer 필드에 일치하는 bean이 두 개 이상 존재하면 modifier로 필드 이름인 "printer"를 사용 public class MemberInfoPrinter2 {
@Autowired private MemberPrinter printer; …… }
명시적 주입과 자동주입을 섞어서 쓰면 디버깅 지옥에 빠진다.
전부다 설정클래스에서 명시적 주입을 시킬 것인지 자동주입을 싹 다 시킬 것인지 명시해줘야
스프링 입장에서 명시적으로 Qualifier 를 써두는게 유지보수에 좋다. 디버깅 지옥에서 빠져나오는 길이다.
담당자가 바뀌면서 성향에 따라 바뀔 때 .. 위험
3. 기본 스캔 대상
@Componet
@Controller
@Service
@Repository
@Service
@Respository
@Aspect
@Configuration
- 컨트롤러 @Controller (프레젠테이션 레이어, 웹 요청과 응답을 처리함)
- 로직 처리 : @Service (서비스 레이어, 내부에서 자바로직을 처리함)
- 외부 I/O 처리 : @Respository (퍼시스턴스 레이어, DB나 파일 같은 외부 I/O작업을 처리함)
package com.gyuone.common;
public class DuplicateMemberException extends RuntimeException{
public DuplicateMemberException(String message) {
super(message);
}
}
MemberNotFoundException.java
package com.gyuone.common;
public class MemberNotFoundException extends RuntimeException{
}
WrongIdPasswordException.java
package com.gyuone.common;
public class WrongIdPasswordException extends RuntimeException{
}
com.gyuone.dao
MemberDao.java
package com.gyuone.dao;
import java.util.HashMap;
import java.util.Map;
import com.gyuone.model.Member;
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);
}
}
com.gyuone.model
Member.java
package com.gyuone.model;
import java.time.LocalDateTime;
import com.gyuone.common.WrongIdPasswordException;
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 registerDateTime) {
super();
this.email = email;
this.password = password;
this.name = name;
this.registerDateTime = registerDateTime; // 생성자 만들어주기
}
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;
}
}
RegisterRequest.java
package com.gyuone.model;
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);
}
}
com.gyuone.service
Assembler.java
package com.gyuone.service;
import com.gyuone.dao.MemberDao;
public class Assembler {
private MemberDao memberDao;
private MemberRegisterService regSvc;
private ChangePasswordService pwdSvc;
public Assembler() {
memberDao = new MemberDao();
regSvc = new MemberRegisterService(memberDao);
pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao);
}
public MemberDao getMemberDao() {
return memberDao;
}
public MemberRegisterService getMemberRegisterService() {
return regSvc;
}
public ChangePasswordService getChangePasswordService() {
return pwdSvc;
}
}
ChangePasswordService.java
package com.gyuone.service;
import com.gyuone.common.MemberNotFoundException;
import com.gyuone.dao.MemberDao;
import com.gyuone.model.Member;
public class ChangePasswordService {
private MemberDao memberDao;
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
public void changePassword(String email, String oldPwd, String newPwd) {
Member member = memberDao.selectByEmail(email);
if(member == null) {
throw new MemberNotFoundException();
}
member.changePassword(oldPwd, newPwd);
memberDao.update(member);
}
}
MemberRegisterService.java
package com.gyuone.service;
import java.time.LocalDateTime;
import com.gyuone.common.DuplicateMemberException;
import com.gyuone.dao.MemberDao;
import com.gyuone.model.Member;
import com.gyuone.model.RegisterRequest;
public class MemberRegisterService {
// private MemberDao memberDao = new MemberDao(); // 강한 결합
private MemberDao memberDao;
public MemberRegisterService(MemberDao memberDao) { // 생성자를 통해서 의존을 주입.. 생성자 의존 주입 = DI
this.memberDao = memberDao;
}
public long register(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();
}
}
MRS와 MDao가강하게 결합되어 있다. 강하게 strongly coupled = > 결합단계를 약하게 만들어야한다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>윈도우 닫기</title>
<script>
let newWin=null; // 새로 연 윈도우 기억
function load(URL) {
newWin = window.open(URL, "myWin", "left=300,top=300,width=400,height=300");
}
function closeNewWindow() {
if(newWin==null || newWin.closed) // 윈도우가 열리지 않았거나 닫힌 경우
return; // 윈도우가 없는 경우 그냥 리턴
else
newWin.close(); // 열어 놓은 윈도우 닫기
}
</script>
</head>
<body>
<h3>window의 close()로 윈도우 닫기</h3>
<hr>
<a href="javascript:load('http://www.disneyworld.com')">
새 윈도우 열기(디즈니월드)</a><br>
<a href="javascript:window.close()">
현재 윈도우 닫기</a><br>
<a href="javascript:closeNewWindow()">
새 윈도우 닫기</a>
</body>
</html>
ex10-3.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>윈도우 닫기</title>
<script>
let newWin=null; // 새로 연 윈도우 기억
function load(URL) {
newWin = window.open(URL, "myWin", "left=300,top=300,width=400,height=300");
}
function closeNewWindow() {
if(newWin==null || newWin.closed) // 윈도우가 열리지 않았거나 닫힌 경우
return; // 윈도우가 없는 경우 그냥 리턴
else
newWin.close(); // 열어 놓은 윈도우 닫기
}
</script>
</head>
<body>
<h3>window의 close()로 윈도우 닫기</h3>
<hr>
<a href="javascript:load('http://www.disneyworld.com')">
새 윈도우 열기(디즈니월드)</a><br>
<a href="javascript:window.close()">
현재 윈도우 닫기</a><br>
<a href="javascript:closeNewWindow()">
새 윈도우 닫기</a>
</body>
</html>
ex10-4.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>setInterval()로 텍스트 회전</title></head>
<body>
<h3>텍스트가 자동 회전하며, 마우스로 클릭하면 중단합니다.</h3>
<hr>
<div><span id="span" style="background-color:yellow">
자동 회전하는 텍스트입니다.</span>
</div>
<script>
let span = document.getElementById("span");
let timerID = setInterval("doRotate()", 200); // 200밀리초 주기로 doRotate() 호출
span.onclick = function (e) { // 마우스 클릭 이벤트 리스너
clearInterval(timerID); // 타이머 해제. 문자열 회전 중단
}
function doRotate() {
let str = span.innerHTML;
let firstChar = str.substr(0, 1);
let remains = str.substr(1, str.length-1);
str = remains + firstChar;
span.innerHTML = str; // str 텍스트를 span 객체에 출력
}
</script>
</body>
</html>
ex10-5.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>윈도우의 위치와 크기 조절</title>
</head>
<body>
<h3>윈도우의 위치와 크기 조절</h3>
<hr>
<button onclick="window.moveBy(-10, 0)">left</button>
<button onclick="window.moveBy(10, 0)">right</button>
<button onclick="self.moveBy(0, -10)">up</button>
<button onclick="moveBy(0, 10)">down</button>
<button onclick="resizeBy(10, 10)">+</button>
<button onclick="resizeBy(-10, -10)">-</button>
</body>
</html>
ex10-6.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>웹 페이지의 자동 스크롤</title>
<script>
function startScroll(interval) {
setInterval("autoScroll()", interval);
}
function autoScroll() {
window.scrollBy(0,10); // 10픽셀 위로 스크롤
}
</script>
</head>
<body onload="startScroll(1000)">
<h3>자동 스크롤 페이지</h3>
<hr>
<h3>꿈길(이동순)</h3>
꿈길에<br>
발자취가 있다면<br>
님의 집 창밖<br>
그 돌계단 길이 이미 오래 전에<br>
모래가 되고 말았을 거예요<br><br>
하지만<br>
그 꿈길에서 자취 없다 하니<br>
나는 그것이 정말 서러워요<br><br>
이 밤도<br>
나는 님의 집 창밖<br>
그 돌계단 위에 홀로 서서<br>
혹시라도 님의 목소리가 들려올까<br>
고개 숙이고 엿들어요<br>
</body>
</html>
ex10-7.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>웹 페이지 프린트</title>
</head>
<body>
<h3>웹 페이지 프린트</h3>
<hr>
<p>window 객체의 print() 메소드를 호출하면
window 객체에 담겨 있는 웹 페이지가 프린트 됩니다.
<p>
<a href="javascript:window.print()">이곳을 누르면 프린트 됩니다.</a><p>
<input type="button" value="프린트" onclick="window.print()">
</body>
</html>
ex10-8.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>onbeforeprint와 onafterprint</title>
<style>
#logoDiv {
display : none;
position : absolute; left : 0; top : 0;
width : 100%; height : 100%;
z-index : -1; /* 로고 이미지를 문서의 밑바닥에 배치 */
}
</style>
<script>
window.onbeforeprint=function (e) {
let logoDiv = document.getElementById("logoDiv");
logoDiv.style.display = "block"; // block으로 변경. 로고가 화면에 나타나게 함
}
window.onafterprint=hideLogo;
function hideLogo() {
let logoDiv = document.getElementById("logoDiv");
logoDiv.style.display = "none"; // 로고를 보이지 않게 함
}
</script></head>
<body>
<h3>onbeforeprint, onafterprint 이벤트 예</h3>
<hr>
<div id="logoDiv">
<img src="media/logo.png" alt="이미지 없습니다.">
</div>
<p>안녕하세요. 브라우저 윈도우에서는 보이지 않지만, 프린트시에는 회사 로고가 출력되는 예제를
보입니다. 마우스 오른쪽 버튼을 눌러 인쇄 미리보기 메뉴를 선택해 보세요.</p>
</body>
</html>
ex10-9.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>window.location으로 웹 사이트 접속</title>
<script>
function load() {
let select = document.getElementById("site");
window.location=select.options[select.selectedIndex].value;
}
</script>
</head>
<body>
<h3>window.location으로 웹 사이트 접속</h3>
<hr>
사이트 선택 :
<select id="site">
<option value="http://www.naver.com" selected>네이버
<option value="http://www.google.com">구글
<option value="http://www.microsoft.com">마이크로소프트
</select>
<p>
<button onclick="load()">웹 사이트 접속</button>
</body>
</html>
ex10-10.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>브라우저 정보 출력</title>
<style>
span { color : blue; }
div {
border-color : yellowgreen;
border-style : solid;
padding : 5px;
}
</style>
<script>
function printNavigator() {
let text = "<span>appCodeName</span>: " + navigator.appCodeName + "<br>";
text += "<span>appName</span>: " + navigator.appName + "<br>";
text += "<span>appVersion</span>: " + navigator.appVersion + "<br>";
text += "<span>platform</span>: " + navigator.platform + "<br>";
text += "<span>product</span>: " + navigator.product + "<br>";
text += "<span>userAgent</span>: " + navigator.userAgent +"<br>";
text += "<span>vendor</span>: " + navigator.vendor +"<br>";
text += "<span>language</span>: " + navigator.language + "<br>";
text += "<span>onLine</span>: " + navigator.onLine + "<br>";
text += "<span>cookieEnabled</span>: " + navigator.cookieEnabled + "<br>";
text += "<span>javaEnabled()</span>:" + navigator.javaEnabled() + "<br>";
text += "<span>plugins.length</span>: " + navigator.plugins.length + "<br>";
for(let j=0; j<navigator.plugins.length; j++) {
text += "plugins" + j + " : <blockquote>";
text += navigator.plugins[j].name + "<br>";
text += "<i>" + navigator.plugins[j].description + "</i><br>";
text += navigator.plugins[j].filename + "</blockquote>";
}
// div 태그에 출력
let div = document.getElementById("div");
div.innerHTML = text;
}
</script>
</head>
<body onload="printNavigator()">
<h3>브라우저에 관한 정보 출력</h3>
아래에 이 브라우저에 관한 여러 정보를 출력합니다.
<hr>
<p>
<div id="div"></div>
</body>
</html>
ex10-11.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>스크린에 관한 정보 출력</title>
<script>
function printScreen() {
let text = "availHeight:" + screen.availHeight + "<br>";
text += "availWidth:" + screen.availWidth + "<br>";
text += "colorDepth:" + screen.colorDepth + "<br>";
text += "pixelDepth:" + screen.pixelDepth + "<br>";
text += "height:" + screen.height + "<br>";
text += "width:" + screen.width + "<br>";
document.getElementById("div").innerHTML = text;
}
</script>
</head>
<body onload="printScreen()">
<h3>스크린 장치에 관한 정보</h3>
<hr>
<div id="div"></div>
</body>
</html>