💙2022-08-12💙

AOP.pdf
0.66MB

 

• AOP (Aspect Oriented Programming)

• cross-cutting concerns - 로깅, 보안, 트랜잭션 관리 등 대부분의 애플리케이션에 공통적으로 사용되는 기능

- 한 애플리케이션의 여러 부분에 걸쳐 있는 기능

- AOP는 이러한 cross-cutting concerns 의 분리를 위한 것

- AOP의 목적은 cross-cutting concerns 와 이에 영향을 받는 객체 간 결합도를 낮추는 것

 

 

Advice 뭔가 해야할 작업 

 

1. AOP 용어 정의

1) Advice ▪ Aspect 가 해야 할 작업

▪ Aspect 의 "What", "When" 을 정의

▪ 스프링 aspect 가 지원하는 advice before :

advice 대상 메서드가 호출되기 전에 advice 기능을 수행

after : 결과에 상관없이 advice 대상 매서드가 완료된 후에 advice 기능을 수행

after-returning : advice 대상 매서드가 성공적으로 완료된 후에 advice 기능을 수행

after-throwing : advice 대상 메서드가 exception을 발생 시킨 후에 advice 기능을 수 행

 around : advice가 advice 대상 메소드를 감싸서 advice 대상 메서드 호출 전/후에 기 능을 수행

 

 

2) Join Points

▪ Advice를 적용할 수 있는 곳 여러 곳이라 s 붙임

▪ 애플리케이션 실행에 aspect를 끼워 넣을 수 있는 지점

▪ 메서드 호출, 예외 발생, 필드 값 수정 등

 

3) Pointcuts

▪ Aspect 가 advice 할 Join Points의 영역을 제한하는 역할

▪ Aspect가 "어디서" 할지를 정의

▪ Advice가 weaving 되어야 하는 하나 이상의 Join Points를 정의

▪ 클래스나 메소드 명을 지정할 수 도 있고, 정규 표현식을 정의 할 수도 있음

 

 

스프링은 매소드 join point 만 지원 필드에 지원하지 않고 메소드에만 지원한다.

 


 

 

 

https://mvnrepository.com/artifact/org.aspectj/aspectjrt/1.9.9.1

https://mvnrepository.com/artifact/org.aspectj/aspectjweaver

pom.xml (runtime은 지우기 )

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.gyuone</groupId>
	<artifactId>aopProject</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>11</maven.compiler.source>
		<maven.compiler.target>11</maven.compiler.target>
	</properties>
	<dependencies>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.3.22</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.9.9.1</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.9.9.1</version>
		</dependency>

	</dependencies>


</project>

 

 

com.gyuone\

concert

Audience.java

package com.gyuone.concert;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class Audience {
	
	@Pointcut("execution(* com.gyuone.concert.Performance.perform(..))")
	public void performance() {}
	
	
//  @Before("execution(* com.gyuone.concert.Performance.perform(..))")
//	@Before("performance()")
//	public void silenceCellPhones() {
//		System.out.println("휴대폰은 꺼주세요!");
//	}
	
//	@Before("execution(* com.gyuone.concert.Performance.perform(..))")
//	@Before("performance()")
//	public void takeSeats() {
//		System.out.println("모두 자리에 앉아주세요!");
//	}
	
//	@AfterReturning("execution(* com.gyuone.concert.Performance.perform(..))")
//	@AfterReturning("performance()")
//	public void applause() {
//		System.out.println("박수~~~~~ 짝짝짝!!");
//	}
	
//	@AfterThrowing("execution(* com.gyuone.concert.Performance.perform(..))")
//	@AfterThrowing("performance()")
//	public void demandRefund() {
//		System.out.println("환불해달라~~~~~~");
//	}
	
	@Around("performance()")
	public void watchPerformance(ProceedingJoinPoint jp) {
		try {
			System.out.println("휴대폰은 꺼주세요!");
			System.out.println("모두 자리에 앉아주세요!");
			jp.proceed();
			System.out.println("박수~~~~~ 짝짝짝!!");
		} catch (Throwable e) {
			// TODO: handle exception
			System.out.println("환불해달라~~~~~~");
		}
	}
	
}

 

 

IUConcert.java

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();
	}
}

 

main

ConcertMain.java

package com.gyuone.main;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

import com.gyuone.concert.IUConcert;
import com.gyuone.concert.Performance;
import com.gyuone.concert.PianoConcert;
import com.gyuone.config.ConcertConfig;

public class ConcertMain {
    public static void main(String[] args) throws Exception{
        AbstractApplicationContext ctx = new AnnotationConfigApplicationContext(ConcertConfig.class);
        
        System.out.println("-------------------<PiaonoConcert>-------------------");
        Performance performance = ctx.getBean("pianoConcert", PianoConcert.class);
        performance.perform();
        
        System.out.println("-------------------<IU Concert>-------------------");
        performance = ctx.getBean("iuConcert", IUConcert.class);
        performance.perform();
        
        ctx.close();
    }
}

 

 


Aspect 정의

  • 공연은 관객 없이는 이루어 질 수 없음
  • 공연 관점에서, 관객은 중요하지만 공연 그 자체의 핵심 기능은 아님
  • 관객을 공연에 적용할 수 있는 aspect로 정의

    ▪ 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 임

 

 

 

'비트교육 > WEB' 카테고리의 다른 글

[38일차] 게시판 만들기  (0) 2022.08.12
[38일차] FirstSpring  (0) 2022.08.12
[37일차] AutoDi  (0) 2022.08.11
[37일차] dISample project  (0) 2022.08.11
[37일차] Spring Bean  (0) 2022.08.11

🤎2022-08-11🤎

 

 

 

https://nodejs.org/download/release/v14.4.0/

 

 

Index of /download/release/v14.4.0/

 

nodejs.org

 

node.js

node-v14.4.0-x64.msi 파일 다운

 

입문 03

 

App.css

.App {
  text-align: center;
}

.App-logo {
  height: 40vmin;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .App-logo {
    animation: App-logo-spin infinite 20s linear;
  }
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

div {
  background-color: rgb(162, 127, 243);
  color: rgb(255, 255, 255);
  padding: 40px;
  font-family: 고딕;
  text-align: center;
}

h1 {
  color: white;
  background-color: #2EFE2E;
  padding: 10px;
  font-family: 궁서;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

 

 

App.js

import React from 'react';
import './App.css';
import ImportConponent from './R003_ImportConponent'

function App() {
  return (
    <div>
      <h1>Start React 200!</h1>
      <p>HTML 적용하기</p>
      <ImportConponent></ImportConponent>
    </div>
  );
}

export default App;

 

R003_ImportConponent.js 

import React, { Component } from 'react';

class R003_ImportConponent extends Component{
  render (){
    return (
      <h2>[ThIS IS IMPORTED COMPONENT]</h2>
    )
  }
}

export default R003_ImportConponent;

 

 


입문 004

생명주기 함수 render() 사용하기

 

R004_LifecycleEx.js

import React, { Component } from 'react';

class R004_LifecycleEx extends Component {
  render() {
    console.log('3. render call');
    return (
      <h2>[THIS IS RENDER FUNCTION]</h2>
    )
  }
}

export default R004_LifecycleEx;

 

 

App.js

import React from 'react';
import './App.css';
import LifecycleEx from './R004_LifecycleEx'

function App() {
  return (
    <div>
      <h1>Start React 200!</h1>
      <p>HTML 적용하기</p>
      <LifecycleEx></LifecycleEx>
    </div>
  );
}

export default App;

 

 

 

'프로그래밍 > React' 카테고리의 다른 글

What is React?  (0) 2025.09.22
React project..  (0) 2023.04.23
React  (0) 2023.04.16
1. react  (0) 2023.01.16
[39일차] 리액트 200제 6~10  (0) 2022.08.16

💛2022-08-11💛

 

 

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;
	}

}

 

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();
	}
}

 

 

main

 

MainForSpring.java

package com.gyuone.main;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.DuplicateFormatFlagsException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.gyuone.common.DuplicateMemberException;
import com.gyuone.common.MemberNotFoundException;
import com.gyuone.common.WrongIdPasswordException;
import com.gyuone.config.AppCtx;
import com.gyuone.model.RegisterRequest;
import com.gyuone.service.ChangePasswordService;
import com.gyuone.service.MemberInfoPrinter;
import com.gyuone.service.MemberListPrinter;
import com.gyuone.service.MemberRegisterService;
import com.gyuone.service.VersionPrinter;

public class MainForSpring {
	private static ApplicationContext ctx = null;
	
	public static void main(String[] args) throws Exception{
		ctx = new AnnotationConfigApplicationContext(AppCtx.class);
		
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		while(true) {
			System.out.print("명령어 입력: ");
			String command = reader.readLine();
			if(command.equalsIgnoreCase("exit")) {
				System.out.println("프로그램 종료");
				break;
			}
			if(command.startsWith("new ")) {
				processNewCommand(command.split(" "));
				continue;
			}else if(command.startsWith("change ")) {
				processChangeCommand(command.split(" "));
				continue;
			}else if(command.startsWith("list")){
				processListCommand();
				continue;
			}else if(command.startsWith("info")) {
				processInfoCommand(command.split(" "));
				continue;
			}else if(command.startsWith("version")) {
				processVersionCommand();
				continue;
			}
			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 processNewCommand(String[] arg) {
		if(arg.length != 5) {
			printHelp();
			return;
		}
		MemberRegisterService regSvc = ctx.getBean(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("암호 확인이 맞지 않습니다.");
			System.out.println();
			return;
		}
		try {
			regSvc.register(req);
			System.out.println("등록 완료");
			System.out.println();
		} catch (DuplicateMemberException e) {
			// TODO: handle exception
			System.out.println("이미 존재하는 이메일입니다.");
			System.out.println();
		}
	}
	
	private static void processChangeCommand(String[] arg) {
		if(arg.length != 4) {
			printHelp();
			return;
		}
		ChangePasswordService changePwdSvc = ctx.getBean(ChangePasswordService.class);
		try {
			changePwdSvc.changePassword(arg[1], arg[2], arg[3]);
			System.out.println("암호 변경 완료");
			System.out.println();
		} catch (MemberNotFoundException e) {
			// TODO: handle exception
			System.out.println("존재하지 않는 이메일입니다.");
			System.out.println();
		} catch (WrongIdPasswordException e) {
			System.out.println("이메일과 암호 불일치합니다.");
			System.out.println();
		}
	}
	
	private static void processListCommand() {
		MemberListPrinter listPrinter = ctx.getBean("listPrinter", MemberListPrinter.class); // "listPrinter", MemberListPrinter.class가 식별자, 타입
		listPrinter.printAll();
	}
	
	private static void processInfoCommand(String[] arg) {
		if(arg.length != 2) {
			printHelp();
			return;
		}
		MemberInfoPrinter infoPrinter = ctx.getBean("infoPrinter", MemberInfoPrinter.class);
		infoPrinter.printMemberInfo(arg[1]);
	}
	
	private static void processVersionCommand() {
		VersionPrinter versionPrinter = ctx.getBean("versionPrinter", VersionPrinter.class);
		versionPrinter.print();
	}
}

 

 

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);
	}
	

}

 

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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.gyuone.common.MemberNotFoundException;
import com.gyuone.dao.MemberDao;
import com.gyuone.model.Member;

@Component
public class ChangePasswordService {
	
	@Autowired
	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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import com.gyuone.dao.MemberDao;
import com.gyuone.model.Member;

@Component("infoPrinter") // 소문자를 바꾼이름으로 주게 되는데 특별한 이름으로 지정해주고 싶을 때 식별자를 준다. 준 이름으로 등록함.
public class MemberInfoPrinter {
	private MemberDao memberDao;
	private MemberPrinter printer;
	
	@Autowired
	public void setMemberDao(MemberDao memberDao) {
		this.memberDao = memberDao;
	}
	
	@Autowired
	@Qualifier("printer")
	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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import com.gyuone.dao.MemberDao;
import com.gyuone.model.Member;

@Component("listPrinter")
public class MemberListPrinter {
	private MemberDao memberDao;
	private MemberPrinter printer;
	
	public MemberListPrinter() {

	}
	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)); 
	}

	@Autowired
	public void setMemberDao(MemberDao memberDao) {
		this.memberDao = memberDao;
	}

	@Autowired
	@Qualifier("summaryPrinter")
	public void setPrinter(MemberPrinter printer) {
		this.printer = printer;
	}
	
	
	

	
}

 

MemberPrinter.java

package com.gyuone.service;

import java.time.format.DateTimeFormatter;

import org.springframework.beans.factory.annotation.Autowired;

import com.gyuone.model.Member;

public class MemberPrinter {
	private DateTimeFormatter dateTimeFormatter;
	
	public MemberPrinter() {
		dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일");
	}
	
	public void print(Member member) {
		if (dateTimeFormatter == null) {
			System.out.printf("회원정보 : 아이디=%d, 이메일=%s, 이름=%s, 등록일=%tF\n", member.getId(),
					member.getEmail(), member.getName(), member.getRegisterDateTime());
		} else {
			System.out.printf("회원정보 : 아이디=%d, 이메일=%s, 이름=%s, 등록일=%s\n", member.getId(),
					member.getEmail(), member.getName(), 
					dateTimeFormatter.format(member.getRegisterDateTime()));
		}
	}

	@Autowired(required = false) // 필수가 아니다. default는 true
	public void setDateTimeFormatter(DateTimeFormatter dateTimeFormatter) {
		this.dateTimeFormatter = dateTimeFormatter;
	}

	
	
	
	
}

 

MemberRegisterService.java

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;
	}
	
}

 

 

 

'비트교육 > WEB' 카테고리의 다른 글

[38일차] FirstSpring  (0) 2022.08.12
[38일차] AOP/ aop concert project  (0) 2022.08.12
[37일차] dISample project  (0) 2022.08.11
[37일차] Spring Bean  (0) 2022.08.11
[36일차] 스프링  (0) 2022.08.10

💛2022-08-11💛

dISample project 

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();
	}
}

 


main

MainForAssembler.java

package com.gyuone.main;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.DuplicateFormatFlagsException;

import com.gyuone.common.MemberNotFoundException;
import com.gyuone.common.WrongIdPasswordException;
import com.gyuone.model.RegisterRequest;
import com.gyuone.service.Assembler;
import com.gyuone.service.ChangePasswordService;
import com.gyuone.service.MemberRegisterService;

public class MainForAssembler {
	private static Assembler assembler = new Assembler();
	
	public static void main(String[] args) throws Exception{
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		while(true) {
			System.out.print("명령어 입력 : ");
			String command = reader.readLine();
			if(command.equalsIgnoreCase("exit")) {
				System.out.println("프로그램 종료");
				break;
			}
			if(command.startsWith("new ")) {
				processNewCommand(command.split(" "));
				continue;
			}else if(command.startsWith("change ")) {
				processChangeCommand(command.split(" "));
				continue;
			}
			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 processNewCommand(String[] arg) {
		if(arg.length != 5) {
			printHelp();
			return;
		}
		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("암호 확인이 맞지 않습니다.");
			System.out.println();
			return;
		}
		try {
			regSvc.register(req);
			System.out.println("등록 완료");
			System.out.println();
		} catch (DuplicateFormatFlagsException e) {
			// TODO: handle exception
			System.out.println("이미 존재하는 이메일입니다.");
			System.out.println();
		}
	}
	
	private static void processChangeCommand(String[] arg) {
		if(arg.length != 4) {
			printHelp();
			return;
		}
		ChangePasswordService changePwdSvc = assembler.getChangePasswordService();
		try {
			changePwdSvc.changePassword(arg[1], arg[2], arg[3]);
			System.out.println("암호 변경 완료");
		} catch (MemberNotFoundException e) {
			// TODO: handle exception
			System.out.println("존재하지 않는 이메일입니다.");
			System.out.println();
		} catch (WrongIdPasswordException e) {
			System.out.println("이메일과 암호 불일치");
			System.out.println();
		}
	}
}

 


 

MainForImport.java

package com.gyuone.main;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.DuplicateFormatFlagsException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.gyuone.common.DuplicateMemberException;
import com.gyuone.common.MemberNotFoundException;
import com.gyuone.common.WrongIdPasswordException;
import com.gyuone.config.AppConfImport;
import com.gyuone.config.AppCtx;
import com.gyuone.model.RegisterRequest;
import com.gyuone.service.ChangePasswordService;
import com.gyuone.service.MemberInfoPrinter;
import com.gyuone.service.MemberListPrinter;
import com.gyuone.service.MemberRegisterService;
import com.gyuone.service.VersionPrinter;

public class MainForImport {
	private static ApplicationContext ctx = null;
	
	public static void main(String[] args) throws Exception{
		ctx = new AnnotationConfigApplicationContext(AppConfImport.class);
		
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		while(true) {
			System.out.print("명령어 입력: ");
			String command = reader.readLine();
			if(command.equalsIgnoreCase("exit")) {
				System.out.println("프로그램 종료");
				break;
			}
			if(command.startsWith("new ")) {
				processNewCommand(command.split(" "));
				continue;
			}else if(command.startsWith("change ")) {
				processChangeCommand(command.split(" "));
				continue;
			}else if(command.startsWith("list")){
				processListCommand();
				continue;
			}else if(command.startsWith("info")) {
				processInfoCommand(command.split(" "));
				continue;
			}else if(command.startsWith("version")) {
				processVersionCommand();
				continue;
			}
			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 processNewCommand(String[] arg) {
		if(arg.length != 5) {
			printHelp();
			return;
		}
		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("암호 확인이 맞지 않습니다.");
			System.out.println();
			return;
		}
		try {
			regSvc.register(req);
			System.out.println("등록 완료");
			System.out.println();
		} catch (DuplicateMemberException e) {
			// TODO: handle exception
			System.out.println("이미 존재하는 이메일입니다.");
			System.out.println();
		}
	}
	
	private static void processChangeCommand(String[] arg) {
		if(arg.length != 4) {
			printHelp();
			return;
		}
		ChangePasswordService changePwdSvc = ctx.getBean("changePwdSvc", ChangePasswordService.class);
		try {
			changePwdSvc.changePassword(arg[1], arg[2], arg[3]);
			System.out.println("암호 변경 완료");
			System.out.println();
		} catch (MemberNotFoundException e) {
			// TODO: handle exception
			System.out.println("존재하지 않는 이메일입니다.");
			System.out.println();
		} catch (WrongIdPasswordException e) {
			System.out.println("이메일과 암호 불일치합니다.");
			System.out.println();
		}
	}
	
	private static void processListCommand() {
		MemberListPrinter listPrinter = ctx.getBean("listPrinter", MemberListPrinter.class); // "listPrinter", MemberListPrinter.class가 식별자, 타입
		listPrinter.printAll();
	}
	
	private static void processInfoCommand(String[] arg) {
		if(arg.length != 2) {
			printHelp();
			return;
		}
		MemberInfoPrinter infoPrinter = ctx.getBean("infoPrinter", MemberInfoPrinter.class);
		infoPrinter.printMemberInfo(arg[1]);
	}
	
	private static void processVersionCommand() {
		VersionPrinter versionPrinter = ctx.getBean("versionPrinter", VersionPrinter.class);
		versionPrinter.print();
	}
}

 


 

MainForSpring.java

package com.gyuone.main;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.DuplicateFormatFlagsException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.gyuone.common.DuplicateMemberException;
import com.gyuone.common.MemberNotFoundException;
import com.gyuone.common.WrongIdPasswordException;
import com.gyuone.config.AppCtx;
import com.gyuone.model.RegisterRequest;
import com.gyuone.service.ChangePasswordService;
import com.gyuone.service.MemberInfoPrinter;
import com.gyuone.service.MemberListPrinter;
import com.gyuone.service.MemberRegisterService;
import com.gyuone.service.VersionPrinter;

public class MainForSpring {
	private static ApplicationContext ctx = null;
	
	public static void main(String[] args) throws Exception{
		ctx = new AnnotationConfigApplicationContext(AppCtx.class);
		
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		while(true) {
			System.out.print("명령어 입력: ");
			String command = reader.readLine();
			if(command.equalsIgnoreCase("exit")) {
				System.out.println("프로그램 종료");
				break;
			}
			if(command.startsWith("new ")) {
				processNewCommand(command.split(" "));
				continue;
			}else if(command.startsWith("change ")) {
				processChangeCommand(command.split(" "));
				continue;
			}else if(command.startsWith("list")){
				processListCommand();
				continue;
			}else if(command.startsWith("info")) {
				processInfoCommand(command.split(" "));
				continue;
			}else if(command.startsWith("version")) {
				processVersionCommand();
				continue;
			}
			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 processNewCommand(String[] arg) {
		if(arg.length != 5) {
			printHelp();
			return;
		}
		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("암호 확인이 맞지 않습니다.");
			System.out.println();
			return;
		}
		try {
			regSvc.register(req);
			System.out.println("등록 완료");
			System.out.println();
		} catch (DuplicateMemberException e) {
			// TODO: handle exception
			System.out.println("이미 존재하는 이메일입니다.");
			System.out.println();
		}
	}
	
	private static void processChangeCommand(String[] arg) {
		if(arg.length != 4) {
			printHelp();
			return;
		}
		ChangePasswordService changePwdSvc = ctx.getBean("changePwdSvc", ChangePasswordService.class);
		try {
			changePwdSvc.changePassword(arg[1], arg[2], arg[3]);
			System.out.println("암호 변경 완료");
			System.out.println();
		} catch (MemberNotFoundException e) {
			// TODO: handle exception
			System.out.println("존재하지 않는 이메일입니다.");
			System.out.println();
		} catch (WrongIdPasswordException e) {
			System.out.println("이메일과 암호 불일치합니다.");
			System.out.println();
		}
	}
	
	private static void processListCommand() {
		MemberListPrinter listPrinter = ctx.getBean("listPrinter", MemberListPrinter.class); // "listPrinter", MemberListPrinter.class가 식별자, 타입
		listPrinter.printAll();
	}
	
	private static void processInfoCommand(String[] arg) {
		if(arg.length != 2) {
			printHelp();
			return;
		}
		MemberInfoPrinter infoPrinter = ctx.getBean("infoPrinter", MemberInfoPrinter.class);
		infoPrinter.printMemberInfo(arg[1]);
	}
	
	private static void processVersionCommand() {
		VersionPrinter versionPrinter = ctx.getBean("versionPrinter", VersionPrinter.class);
		versionPrinter.print();
	}
}

 


 

MainForSpring2.java

package com.gyuone.main;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.gyuone.common.DuplicateMemberException;
import com.gyuone.common.MemberNotFoundException;
import com.gyuone.common.WrongIdPasswordException;
import com.gyuone.config.AppConf1;
import com.gyuone.config.AppConf2;
import com.gyuone.model.RegisterRequest;
import com.gyuone.service.ChangePasswordService;
import com.gyuone.service.MemberInfoPrinter;
import com.gyuone.service.MemberListPrinter;
import com.gyuone.service.MemberRegisterService;
import com.gyuone.service.VersionPrinter;

public class MainForSpring2 {
	private static ApplicationContext ctx = null;
	
	public static void main(String[] args) throws Exception{
		ctx = new AnnotationConfigApplicationContext(AppConf1.class, AppConf2.class);
		
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		while(true) {
			System.out.print("명령어 입력: ");
			String command = reader.readLine();
			if(command.equalsIgnoreCase("exit")) {
				System.out.println("프로그램 종료");
				break;
			}
			if(command.startsWith("new ")) {
				processNewCommand(command.split(" "));
				continue;
			}else if(command.startsWith("change ")) {
				processChangeCommand(command.split(" "));
				continue;
			}else if(command.startsWith("list")){
				processListCommand();
				continue;
			}else if(command.startsWith("info")) {
				processInfoCommand(command.split(" "));
				continue;
			}else if(command.startsWith("version")) {
				processVersionCommand();
				continue;
			}
			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 processNewCommand(String[] arg) {
		if(arg.length != 5) {
			printHelp();
			return;
		}
		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("암호 확인이 맞지 않습니다.");
			System.out.println();
			return;
		}
		try {
			regSvc.register(req);
			System.out.println("등록 완료");
			System.out.println();
		} catch (DuplicateMemberException e) {
			// TODO: handle exception
			System.out.println("이미 존재하는 이메일입니다.");
			System.out.println();
		}
	}
	
	private static void processChangeCommand(String[] arg) {
		if(arg.length != 4) {
			printHelp();
			return;
		}
		ChangePasswordService changePwdSvc = ctx.getBean("changePwdSvc", ChangePasswordService.class);
		try {
			changePwdSvc.changePassword(arg[1], arg[2], arg[3]);
			System.out.println("암호 변경 완료");
			System.out.println();
		} catch (MemberNotFoundException e) {
			// TODO: handle exception
			System.out.println("존재하지 않는 이메일입니다.");
			System.out.println();
		} catch (WrongIdPasswordException e) {
			System.out.println("이메일과 암호 불일치합니다.");
			System.out.println();
		}
	}
	
	private static void processListCommand() {
		MemberListPrinter listPrinter = ctx.getBean("listPrinter", MemberListPrinter.class); // "listPrinter", MemberListPrinter.class가 식별자, 타입
		listPrinter.printAll();
	}
	
	private static void processInfoCommand(String[] arg) {
		if(arg.length != 2) {
			printHelp();
			return;
		}
		MemberInfoPrinter infoPrinter = ctx.getBean("infoPrinter", MemberInfoPrinter.class);
		infoPrinter.printMemberInfo(arg[1]);
	}
	
	private static void processVersionCommand() {
		VersionPrinter versionPrinter = ctx.getBean("versionPrinter", VersionPrinter.class);
		versionPrinter.print();
	}
}

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);
	}
	

}

 

 


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;
	}
	
}

 

'비트교육 > WEB' 카테고리의 다른 글

[38일차] AOP/ aop concert project  (0) 2022.08.12
[37일차] AutoDi  (0) 2022.08.11
[37일차] Spring Bean  (0) 2022.08.11
[36일차] 스프링  (0) 2022.08.10
[36일차] Servlet. jsp  (0) 2022.08.10

💕2022-08-11💕

 

스프링객체가  생성 관리하는 객체 = bean

스프링 bean

 

객체는 객체인데 스프링을 관리 기본적으로 싱글톤 하나만 만든다.

스프링은 포조기반

스프링 설정으로 지정 @Configuration

 


 

@Bean 

 

- 스프링은 객체를 생성하고 초기화 하는 기능을 제공

- 스프링이 생성하고 관리하는 객체를 Bean 객체라 함

- 객체를 생성하고 리턴하는 메소드에 @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작업을 처리함)

 


 

'비트교육 > WEB' 카테고리의 다른 글

[38일차] AOP/ aop concert project  (0) 2022.08.12
[37일차] AutoDi  (0) 2022.08.11
[37일차] dISample project  (0) 2022.08.11
[36일차] 스프링  (0) 2022.08.10
[36일차] Servlet. jsp  (0) 2022.08.10

 

 

🧡2022-08-10🧡

 

 

https://blog.naver.com/writer0713/220700687650

 

 

 

[java] POJO란?

자바와 스프링 공부를 하면서 여러 자료를 찾아보는데 항상 POJO라는 단어가 많이 등장했다. 도대체 P...

blog.naver.com

 

EJBC (Enterprise Java Bean)

자바 개발자들이 피곤해지기 시작.. EJB를 만들때 기본적인 객체지향 개념이 잘못된 ,. 클래스를 잘못 만들어서

보안 관련 EJB extend 얽히고 섥힌.. 줄줄이 끌려오는게 많아서 무거워짐 -> 클래스 설계 잘못

 

객체지향 컨퍼런스 

POJO Plain Java Object

객체지향 개념을 지향하면서 자바 오브젝트의 특징을 갖고있는..  그럴듯하니깐 포조운동이 일어남

 

기술면접에서도 나올 수 있음. 라이브러리와 프레임워크의 차이가 뭐냐,,,

라이브러리에도 나와도 좋고 프레임워크에서 나와도 좋은

라이브러리는 특정한 기능들 함수나 클래스로 끌어다 쓰는 것

ex) 태그 라이브러리 JAR 파일.. 

프레임워크는 라이브러리가 모여서 와꾸.. 탁 트인 것 

어떤 기능은 여기다가 적어라 틀에 못벗어남.. 물리적으로 보면 프레임워크는 라이브러리의 집합체

포조를 기반으로 한 프레임워크가 등장한다.

structs, spring 이 등장하였다 ! !

시간이 지나면서 스프링이 완성됨

Spring 자바의 봄을 맞이했다.. 해서 스프링

 

스프링?? 웹 애플리케이션과 무슨 상관이냐??

스프링이란 DI와 AOP를 지원하는 POJO 기반의 Framework이다!

 

DI가 뭐고 AOP가 무엇인지 알아야 스프링을 이해할 수 있다.

 

1. DI (Dependency Injection = 의존 주입)

스프링이 아니고 객체지향 디자인과 관련되어있음.

 

 

메이븐 프로젝트 pom 바꾸기

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.gyuone</groupId>
  <artifactId>dISample</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <properties>
  	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  	<maven.compiler.source>11</maven.compiler.source>
  	<maven.compiler.target>11</maven.compiler.target>
  </properties>
</project>

https://mvnrepository.com/artifact/org.springframework/spring-context/5.3.22

 

 

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.gyuone</groupId>
	<artifactId>dISample</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>11</maven.compiler.source>
		<maven.compiler.target>11</maven.compiler.target>
	</properties>
	<dependencies>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.3.22</version>
		</dependency>
	</dependencies>
</project>

 

 

 

끌고 온거 확인


 

 

depends on 의존 관계 memberDao는 MRS의 dependency..

memberRegisterService는 memberDao가 꼭 들어가야하는 dependency

 

dependency.. 의존, 의존성

 


https://github.com/GyuWonLee/dIProject

 

GitHub - GyuWonLee/dIProject

Contribute to GyuWonLee/dIProject development by creating an account on GitHub.

github.com

 

com.gyuone.main

MainForAssembler.java

package com.gyuone.main;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.DuplicateFormatFlagsException;

import com.gyuone.common.MemberNotFoundException;
import com.gyuone.common.WrongIdPasswordException;
import com.gyuone.model.RegisterRequest;
import com.gyuone.service.Assembler;
import com.gyuone.service.ChangePasswordService;
import com.gyuone.service.MemberRegisterService;

public class MainForAssembler {
	private static Assembler assembler = new Assembler();
	
	public static void main(String[] args) throws Exception{
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		while(true) {
			System.out.print("명령어 입력 : ");
			String command = reader.readLine();
			if(command.equalsIgnoreCase("exit")) {
				System.out.println("프로그램 종료");
				break;
			}
			if(command.startsWith("new ")) {
				processNewCommand(command.split(" "));
				continue;
			}else if(command.startsWith("change ")) {
				processChangeCommand(command.split(" "));
				continue;
			}
			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 processNewCommand(String[] arg) {
		if(arg.length != 5) {
			printHelp();
			return;
		}
		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("암호 확인이 맞지 않습니다.");
			System.out.println();
			return;
		}
		try {
			regSvc.register(req);
			System.out.println("등록 완료");
			System.out.println();
		} catch (DuplicateFormatFlagsException e) {
			// TODO: handle exception
			System.out.println("이미 존재하는 이메일입니다.");
			System.out.println();
		}
	}
	
	private static void processChangeCommand(String[] arg) {
		if(arg.length != 4) {
			printHelp();
			return;
		}
		ChangePasswordService changePwdSvc = assembler.getChangePasswordService();
		try {
			changePwdSvc.changePassword(arg[1], arg[2], arg[3]);
			System.out.println("암호 변경 완료");
		} catch (MemberNotFoundException e) {
			// TODO: handle exception
			System.out.println("존재하지 않는 이메일입니다.");
			System.out.println();
		} catch (WrongIdPasswordException e) {
			System.out.println("이메일과 암호 불일치");
			System.out.println();
		}
	}
}

 

com.gyuone.common

DuplicateMemverException.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{
	
}

 

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 = > 결합단계를 약하게 만들어야한다.

 

'비트교육 > WEB' 카테고리의 다른 글

[38일차] AOP/ aop concert project  (0) 2022.08.12
[37일차] AutoDi  (0) 2022.08.11
[37일차] dISample project  (0) 2022.08.11
[37일차] Spring Bean  (0) 2022.08.11
[36일차] Servlet. jsp  (0) 2022.08.10

💙2022-08-10💙

 

헤더 부분이 있고

response는 실제 html 소스 전달하려는 내용이 들어있다.

초창기 WWW 맵의 모습.. 여기서 알 수 있듯이 옛날 부터 거슬러 올라가자면, 

미리 만들어둔 html 문서를 보여준다. 철저히 static한 리소스만을 보여준다. 미리 만들어둔..

브라우저 화면에 칸에다가 자기 학번을 집어 넣고서 버튼을 눌렀을 때 본인에 대한 자료

다이나믹한 자료,,, static 다이나믹 그림이 움직이냐 안움직이냐 그게 아니라 static하냐 dynamic하냐,,,

사용자 요청에 따라서 구분해서 동작하는게 필요하다.

새로운 시도 -> 자바 기준 ! 사용자가 요청하는 거에 따라서 다른 동작을 해주려면 자바로 짠 비즈니스 로직이 필요하다.

servelt 서블릿 

서블릿이란 Dynamic Web Page를 만들 때 사용되는 자바 기반의 웹 애플리케이션 프로그래밍 기술입니다

 

웹 애플리케이션 서버다. WAS로 줄여서 쓴다. Apache Tomcat 무료 버전 web sphere JEWS 국산 신기술

 

9.0.65 다운로드

 

 

윈도우 start 

 

other - server

 

doget get방식으로 호출할 때 default는 get 방식 

언제 어떤 방식 매핑

 

first라는 주소로 올 때 서블렛 매핑

 

loginServlet 

 

 

login.html

 

 

server 켜서 login.html

 

 

 

 

 


 

 

LoginServlet.java



package com.gyuone.test01;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class LoginServlet
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

/**
 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
 */
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("utf-8");
String user_id = request.getParameter("user_id"); /* 입력 안에 있는 nameparameter 서버랑 attribute를 맞춘다.*/
String user_pw = request.getParameter("user_pw");
System.out.println("아이디: " + user_id);
System.out.println("패스워드: " + user_pw);

}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
req.setCharacterEncoding("utf-8");
String user_id = req.getParameter("user_id"); /* 입력 안에 있는 nameparameter 서버랑 attribute를 맞춘다.*/
String user_pw = req.getParameter("user_pw");

resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();

StringBuffer sb = new StringBuffer();
sb.append("<html>");
sb.append("<body>");
sb.append("아이디");
sb.append(user_id);
sb.append("<br>");
sb.append("비밀번호 : ");
sb.append(user_pw);
sb.append("</body>");
sb.append("</html>");
out.print(sb.toString());
}
}

 

 


package com.gyuone.test01;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class LoginServlet
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		request.setCharacterEncoding("utf-8");
		String user_id = request.getParameter("user_id"); /* 입력 안에 있는 nameparameter 서버랑 attribute를 맞춘다.*/
		String user_pw = request.getParameter("user_pw");
		System.out.println("아이디: " + user_id);
		System.out.println("패스워드: " + user_pw);
		
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		req.setCharacterEncoding("utf-8");
		String user_id = req.getParameter("user_id"); /* 입력 안에 있는 nameparameter 서버랑 attribute를 맞춘다.*/
		String user_pw = req.getParameter("user_pw");
		
		resp.setContentType("text/html;charset=utf-8");
		PrintWriter out = resp.getWriter();
		
		StringBuffer sb = new StringBuffer();
		sb.append("<html>");
		sb.append("<body>");
		sb.append("아이디 : ");
		sb.append(user_id);
		sb.append("<br>");
		sb.append("비밀번호 : ");
		sb.append(user_pw);
		sb.append("</body>");
		sb.append("</html>");	
		out.print(sb.toString());
	}
}


 

 

JSP (Java Server Page)

  • 초기 웹 프로그램은 서블릿을 이용해서 구현
  • 화면의 기능이나 구성이 복잡해짐에 따라 프로그래머가 서블릿으로 화면을 구현하지 않고 주로 디자이너가 이 일을 담당
  • 서블릿의 기능 중 별도로 화면 기능을 디자이너가 작업하기 쉽게 하기 위해 JSP가 등장
  • JSP는 디자이너 입장에서 화면의 수월한 기능 구현과 개발 후 화면의 편리한 유지관리를 목적으로 도입
  • JSP는 HTML, CSS와 자바스크립트를 기반으로 JSP 요소들을 사용해 화면을 구현

E:\source\java\eclipse-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\ServletTest\org\apache\jsp

 


hello2.jsp

 


hello3.jsp

 


	<%@ page language="java" contentType="text/html; charset=UTF-8"
	    import="java.util.*"
	    import="sec02.ex01.*"
	    pageEncoding="UTF-8"
	%>
	<!DOCTYPE html>
	<html>
	<head>
	<style>
	h1 {
	text-align: center;
	}
	</style>
	  <meta charset="UTF-8">
	<title>회원 정보 출력창</title>
	</head>
	<body>
	<h1>회원 정보 출력</h1>
	<%
	   request.setCharacterEncoding( "utf-8" );
	   String _name = request.getParameter("name");
	   CustomerVO customerVO = new CustomerVO();
	   customerVO.setCustName(_name);
	   CustomerDAO dao=new CustomerDAO();
	   List<CustomerVO> customersList=dao.listCustomers(customerVO);
	%>
	 <table border='1' width='800' align='center'>
	   <tr align='center' bgcolor='#FFFF66'> 
	     <td>아이디</td>
	     <td>비밀번호</td>
	     <td>이름</td>
	     <td >이메일</td>
	     <td>가입일자</td>
	</tr>
	<%	
	   for (int i=0; i < customersList.size(); i++){
			CustomerVO vo=(CustomerVO) customersList.get(i);
			String id=vo.getCustId();
	      	String pwd=vo.getPhone();
	      	String name=vo.getCustName();
	      	String addr=vo.getAddr();
	      	String regDate=vo.getRegDate();
	%>
	     <tr align=center>
	       <td><%= id %></td>
	       <td><%= pwd %></td>
	       <td><%= name %></td>
	       <td><%= addr %></td>
	       <td><%=regDate  %></td>
	     </tr>
	   
	<%		
	   }
	%>	
	</table>
	</body>
</html>

el-ignored 

 

 

 


customer1.jsp

	<%@ page language="java" contentType="text/html; charset=UTF-8"
	    pageEncoding="UTF-8" isELIgnored="false"  %>
	<%
	   request.setCharacterEncoding("UTF-8");
	   String custId=request.getParameter("custId");
	   String pwd=request.getParameter("phone");
	   String custName= request.getParameter("custName");
	   String addr= request.getParameter("addr");
	   String birthDate= request.getParameter("birthDate");
	  
	%>   
	<html>
	<head>
	<meta charset="UTF-8">
	<title>회원 정보 출력창</title>
	</head>
	<body>
	<table border="1"  align="center" >
	    <tr align="center" bgcolor="#99ccff">
	      <td width="20%"><b>아이디</b></td>
	      <td width="20%"><b>비밀번호</b></td>
	      <td width="20%" ><b>이름</b></td>
	      <td width="20%"><b>주소</b></td>
	      <td width="20%"><b>생일</b></td>
	   </tr>
	   <tr align=center>
	      <td><%=custId %> </td>
	      <td><%=pwd%> </td>
	      <td><%=custName %> </td>
	      <td><%=addr %> </td>
	      <td><%=birthDate %> </td>
	   </tr>   
	   <tr align=center>
	      <td>${param.custId } </td>
	      <td>${param.phone } </td>
	      <td>${param.custName } </td>
	      <td>${param.addr }</td>
	      <td>${param.birthDate }</td>
	   </tr>
	</table>
	</body>
</html>

 

customerForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 가입창</title>
<body>
	<form method="post" action="customer1.jsp">
		<h1 style="text-align: center">회원 가입창</h1>
		<table align="center">
			<tr>
				<td width="200"><p align="right">아이디</td>
				<td width="400"><input type="text" name="custId"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">비밀번호</td>
				<td width="400"><input type="password" name="phone"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">이름</td>
				<td width="400"><p>
						<input type="text" name="custName"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">주소</td>
				<td width="400"><p>
						<input type="text" name="addr"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">생일</td>
				<td width="400"><p>
						<input type="text" name="birthDate"></td>
			</tr>
			<tr>
				<td width="200"><p>&nbsp;</p></td>
				<td width="400"><input type="submit" value="가입하기"> <input
					type="reset" value="다시입력"></td>
			</tr>
		</table>
	</form>
</body>
</html>

 

 

<%
   request.setCharacterEncoding("UTF-8");
   String custId=request.getParameter("custId");
   String pwd=request.getParameter("phone");
   String custName= request.getParameter("custName");
   String addr= request.getParameter("addr");
   String birthDate= request.getParameter("birthDate");
  
%>   

 

위에는 이거를 가져와야하기 때문에 param을 많이 쓰게 된다.

 


JSTL

JSTL의 정식 명칭은 자바서버 페이지 표준 태그 라이브러리(JavaServer Pages Standard Tag Library)이고 줄여서 JSTL이라 부른다.

 

https://tomcat.apache.org/download-taglibs.cgi

 

Apache Tomcat® - Apache Taglibs Downloads

Welcome to the Apache Taglibs download page. This page provides download links for obtaining the latest version of the Apache Standard Taglib, as well as links to the archives of older releases. You must verify the integrity of the downloaded files. We pro

tomcat.apache.org

 

다운로드 받기 4개다 webapp에 붙여넣기

 

 

국제화 - 다국어

 

 


customer2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
  request.setCharacterEncoding("UTF-8");
%>  

<c:set  var="id"  value="hong"  scope="page" />
<c:set  var="pwd"  value="1234"  scope="page" />
<c:set  var="name"  value="${'홍길동'}"  scope="page" />
<c:set  var="age"  value="${22}"  scope="page" />
<c:set  var="height"  value="${177}"  scope="page" />

<html>
<head>
  <meta charset=”UTF-8">
  <title>회원 정보 출력창</title>
</head>
<body>
<table  align="center"  border=1  >
   <tr align="center"  bgcolor="lightgreen" >
      <td width="7%" ><b>아이디</b></td>
      <td width="7%" ><b>비밀번호</b></td>
      <td width="7%" ><b>이름</b></td>
      <td width="7%"><b>나이</b></td>
      <td width="7%" ><b>키</b></td>
   </tr>
   <tr align="center">
      <td>${id}</td>
      <td>${pwd}</td>
      <td>${name}</td>
      <td>${age}</td>
      <td>${height}</td>
	   </tr>
</table>
</body>
</html>

 


customer3.jsp

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
     import="java.util.*" pageEncoding="UTF-8"  isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
  List<String> dataList=new ArrayList<String>();
  dataList.add("hello");
  dataList.add("world");
  dataList.add("안녕하세요!!");
%>
<c:set  var="list"  value="<%=dataList  %>" />
<html>
<head>
<meta charset=”UTF-8">
<title>반복문 실습</title>
</head>
<body>
   <c:forEach  var="i" begin="1" end="10" step="1"  varStatus="loop">
    i=  ${i}   &nbsp;&nbsp;&nbsp;  반복횟수: ${loop.count} <br>
   </c:forEach>
 <br>
   <c:forEach  var="i" begin="1" end="10" step="2" >
        5 * ${i} = ${5*i}<br>
   </c:forEach>
<br>
   <c:forEach  var="data" items="${list}" >
       ${data } <br> 
   </c:forEach>
<br>
<c:set var="fruits" value="사과, 파인애플, 바나나, 망고, 귤"  />
<c:forTokens  var="token" items="${fruits}" delims="," >
    ${token} <br> 
</c:forTokens>
	</body>
</html>

 

 

 


MVC Model View Controller 

 

Django에서는 MVT 패턴..


 

'비트교육 > WEB' 카테고리의 다른 글

[38일차] AOP/ aop concert project  (0) 2022.08.12
[37일차] AutoDi  (0) 2022.08.11
[37일차] dISample project  (0) 2022.08.11
[37일차] Spring Bean  (0) 2022.08.11
[36일차] 스프링  (0) 2022.08.10

💚2022-08-08💚

 

https://thebook.io/080313/part04/ch13/

 

코딩 자율학습 HTML + CSS + 자바스크립트: 13장 HTML+CSS+자바스크립트로 완성하는 최종 프로젝트

 

thebook.io

 

https://github.com/GyuWonLee/homepage.git

 

GitHub - GyuWonLee/homepage

Contribute to GyuWonLee/homepage development by creating an account on GitHub.

github.com

 

 

index.html

<!DOCTYPE html>
<html lang="zxx">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Final Project</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  <link rel="stylesheet" href="style.css">
<style>
  /* width */
  ::-webkit-scrollbar {
    width: 20px;
    border-radius: 10px;
    background: #000000;
  }

  /* Track */
  ::-webkit-scrollbar-track {
    background: #BDBDBD;
    border-radius: 10px;

  }

  /* Handle */
  ::-webkit-scrollbar-thumb {
    background: #ED4848;
    border-radius: 10px;
  }

  /* Handle on hover */
  ::-webkit-scrollbar-thumb:hover {
    background: #ED4848;
    border-radius: 10px;

  }

  *{
    font-family: 'KOTRA_BOLD-Bold';
  }

  @font-face {
    src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_20-10-21@1.1/KOTRA_BOLD-Bold.woff') format('woff');
    font-weight: normal;
    font-style: normal;
}
</style>

</head>
<body>
  <!-- header -->
  <header>
    <div class="container">
      <h1>
        <button data-animation-scroll="true" data-target="#main">BLOG</button>
      </h1>
      <nav>
        <ul>
          <li>
            <button data-animation-scroll="true" data-target="#about">
              About
            </button>
          </li>
          <li>
            <button data-animation-scroll="true" data-target="#features">
              Features
            </button>
          </li>
          <li>
            <button data-animation-scroll="true" data-target="#portfolio">
              Portfolio
            </button>
          </li>
          <li>
            <button data-animation-scroll="true" data-target="#contact">
              Contact
            </button>
          </li>
        </ul>
      </nav>
    </div>
  </header>
  <!-- //end header -->
  <!-- main -->
  <main id="main">
    <div class="container">
      <h4>Welcome</h4>
      <h2 class="active">I`M A <span></span></h2>
      <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium dolor quas nulla unde ea officiis?</p>
      <button class="download">DOWNLOAD CV</button>
      <button class="mouse"><i class="fa-solid fa-computer-mouse"></i></button>
    </div>
  </main>
  <!-- //end Main -->
  <!-- About Me -->
  <section id="about" class="about">
    <div class="container">
      <div class="title">
        <h4>Who Am I</h4>
        <h2>About Me</h2>
      </div>
      <div class="about-self">
        <div class="left">
          <img src="images/me_alone.jpg" alt="">
        </div>
        <div class="right">
          <h3>Hello, <strong>I`m Sucoding</strong></h3>
          <p>I`m Web Publisher And Web Front-End Developer.</p>
          <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe veritatis aperiam accusantium.</p>
          <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Sit praesentium doloremque quos quis est officiis.</p>
          <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Autem, omnis quibusdam.</p>
          <div class="social">
            <a href="#">
              <i class="fa-brands fa-facebook"></i>
            </a>
            <a href="#">
              <i class="fa-brands fa-instagram"></i>
            </a>
            <a href="#">
              <i class="fa-brands fa-twitch"></i>
            </a>
            <a href="#">
              <i class="fa-brands fa-youtube"></i>
            </a>
          </div>
        </div>
      </div>
    </div>
  </section>
  <!-- end About Me -->
  <!-- What I Do -->
  <section id="features" class="do">
    <div class="container">
      <div class="title">
        <h4>Features</h4>
        <h2>What I Do</h2>
      </div>
      <div class="do-me">
        <div class="do-inner">
          <div class="icon">
            <i class="fa-brands fa-html5"></i>
          </div>
          <div class="content">
            <h3>HTML5</h3>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo culpa magni laboriosam sit excepturi quibusdam adipisci, vero debitis?</p>
          </div>
        </div>
        <div class="do-inner">
          <div class="icon">
            <i class="fa-brands fa-css3-alt"></i>
          </div>
          <div class="content">
            <h3>CSS3</h3>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo culpa magni laboriosam sit excepturi quibusdam adipisci, vero debitis?</p>
          </div>
        </div>
        <div class="do-inner">
          <div class="icon">
            <i class="fa-brands fa-bootstrap"></i>
          </div>
          <div class="content">
            <h3>BootStrap v5.0</h3>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo culpa magni laboriosam sit excepturi quibusdam adipisci, vero debitis?</p>
          </div>
        </div>
      </div>
    </div>
  </section>
  <!-- //end What I Do -->
  <!-- Background -->
  <div class="bg"></div>
  <!-- //end Background-->
  <!-- PortFolio -->
  <section id="portfolio" class="portfolio">
    <div class="container">
      <div class="title">
        <h4>PORTFOLIOBACK</h4>
        <h2>PortFolio</h2>
      </div>
      <div class="portfolio-me">
        <div class="portfolio-inner">
          <img src="images/mock1.png" alt="">
          <strong>BRANDING</strong>
          <h3>Package Design</h3>
        </div>
        <div class="portfolio-inner">
          <img src="images/mock2.png" alt="">
          <strong>DEVELOPMENT</strong>
          <h3>Tablet App Dev</h3>
        </div>
        <div class="portfolio-inner">
          <img src="images/mock3.png" alt="">
          <strong>MARKETING</strong>
          <h3>Coka Cola </h3>
        </div>
        <div class="portfolio-inner">
          <img src="images/mock4.png" alt="">
          <strong>APP</strong>
          <h3>FaceBook Clone</h3>
        </div>
        <div class="portfolio-inner">
          <img src="images/mock5.png" alt="">
          <strong>APP</strong>
          <h3>Netflix Clone</h3>
        </div>
        <div class="portfolio-inner">
          <img src="images/mock6.png" alt="">
          <strong>WEB</strong>
          <h3>FirmBee Web</h3>
        </div>
      </div>
    </div>
  </section>
  <!-- //end PortFolio -->
   <!-- Contact With Me -->
   <section id="contact" class="contact">
    <div class="container">
      <div class="title">
        <h4>CONTACT</h4>
        <h2>Contact With Me</h2>
      </div>
      <div class="contact-me">
        <div class="left">
          <div class="card">
            <div class="icon">
              <i class="fa-solid fa-phone-volume"></i>
            </div>
            <div class="info-text">
              <h3>phone</h3>
              <p>010-2222-1111</p>
            </div>
          </div>
          <div class="card">
            <div class="icon">
              <i class="fa-solid fa-envelope-open-text"></i>
            </div>
            <div class="info-text">
              <h3>email</h3>
              <p>sucoding@naver.com</p>
            </div>
          </div>
          <div class="card">
            <div class="icon">
              <i class="fa-solid fa-location-crosshairs"></i>
            </div>
            <div class="info-text">
              <h3>address</h3>
              <p>Samseong-ro, Gangnam-gu, Seoul, Republic of Korea</p>
            </div>
          </div>
        </div>
        <div class="right">
          <form action="#">
            <div class="form-group">
              <label for="name">name</label>
              <input type="text" id="name">
            </div>
            <div class="form-group">
              <label for="email">email</label>
              <input type="text" id="email">
            </div>
            <div class="form-group">
              <label for="msg">message</label>
              <textarea id="msg"></textarea>
            </div>
            <button>send</button>
          </form>
        </div>
      </div>
    </div>
  </section>
  <!-- end Contact With Me -->
  <!-- script 태그는 수정하지 않습니다. -->
  <script src="script.js"></script>
</body>
</html>

 

script.js

/* text_iife.js */
// 텍스트 작성과 삭제 즉시 실행 함수
(function(){
  const spanEl = document.querySelector("main h2 span");
  const txtArr = ['Web Publisher', 'Front-End Developer', 'Web UI Designer', 'UX Designer', 'Back-End Developer'];
  let index = 0;
  let currentTxt = txtArr[index].split("");
  function writeTxt(){
    spanEl.textContent  += currentTxt.shift();
    if(currentTxt.length !== 0){
      setTimeout(writeTxt, Math.floor(Math.random() * 100));
    }else{
      currentTxt = spanEl.textContent.split("");
      setTimeout(deleteTxt, 3000);
    }
  }
  function deleteTxt(){
    currentTxt.pop();
    spanEl.textContent = currentTxt.join("");
    if(currentTxt.length !== 0){
      setTimeout(deleteTxt, Math.floor(Math.random() * 100))
    }else{
      index = (index + 1) % txtArr.length;
      currentTxt = txtArr[index].split("");
      writeTxt();
    }
  }
  writeTxt();
})();
/* end text_iife.js */

/* scroll_request.js */
/* 수직 스크롤이 발생하면 header 태그에 active 클래스 추가 및 삭제 */
const headerEl = document.querySelector("header");
window.addEventListener('scroll', function(){
  requestAnimationFrame(scrollCheck);
});
function scrollCheck(){
  let browerScrollY = window.scrollY ? window.scrollY : window.pageYOffset;
  if(browerScrollY > 0){
    headerEl.classList.add("active");
  }else{
    headerEl.classList.remove("active");
  }
}
/* end scroll_request.js */

/* move.js */
/* 애니메이션 스크롤 이동 */
const animationMove = function(selector){
  // ① selector 매개변로 이동할 대상 요소 노드 가져오기
  const targetEl = document.querySelector(selector);
  // ② 현재 브라우저의 스크롤 정보(y 값)
  const browserScrollY = window.pageYOffset;
  // ③ 이동할 대상의 위치(y 값)
  const targetScorllY = targetEl.getBoundingClientRect().top + browserScrollY;
  // ④ 스크롤 이동
  window.scrollTo({ top: targetScorllY, behavior: 'smooth' });
};
// 스크롤 이벤트 연결하기
const scollMoveEl = document.querySelectorAll("[data-animation-scroll='true']");
for(let i = 0; i < scollMoveEl.length; i++){
  scollMoveEl[i].addEventListener('click', function(e){
    const target = this.dataset.target;
    animationMove(target);
  });
}
/* End move.js */

 

 

style.css

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&family=Varela+Round&display=swap');
/* header.css */
*{
  margin:0;
  padding:0;
  box-sizing:border-box;
  font-family: 'GangwonEduPowerExtraBoldA';
}

* {
  font-family: 'ONE-Mobile-POP';
}
a, a:link, a:visited{
  color:inherit;
  text-decoration:none;
}
li{
  list-style:none;
}
.container{
  width:1140px;
  margin:0 auto;
}
header{
  position:fixed;
  color:white;
  top:0;
  z-index:1;
  width:100%;
  padding:1rem;
}
header .container{
  display:flex;
  justify-content:space-between;
  align-items:center;
  width:100%;
}
header nav ul{
  display:flex;
}
header nav ul li{
  padding:10px;
}
header button{
  background: transparent;
  border:0;
  cursor: pointer;
  color:white;
}
header h1 button{
  font-size: 2rem;
  font-weight: bold;
}
header nav ul li button{
  font-size: 1.2rem;
}
/* End header.css */
/* main.css */
main{
  width:100%;
  height:100vh;
  color:white;
  background:linear-gradient(rgba(0,0,0,0.8), rgba(0,0,0,0.8)), url('images/me.jpg') center center;
  background-size:cover;
  display:flex;
  justify-content:center;
  align-items:center;
  text-align:center;
}
main h4{
  font-size:2rem;
}
main h2{
  font-size:3.5rem;
  margin:2rem 0;
  letter-spacing:3px;
  font-family:'Varela Round', sans-serif; /* 웹 폰트 추가 */
}
main p{
  max-width:500px;
  margin:0 auto;
  font-size:1.25rem;
}
main button.download{
  background-color:transparent;
  border:3px solid white;
  border-radius:20px;
  padding:1rem 2rem;
  margin-top:3rem;
  color:white;
  font-weight:bold;
  cursor:pointer;
}
main button.mouse{
  background-color:transparent;
  border:none;
  color:white;
  font-size:2rem;
  position:absolute;
  bottom:1rem;
  left:50%;
  transform:translateX(-50%);
  animation:upDown 1s ease-in-out infinite;
  cursor:pointer;
}
@keyframes upDown{
  0%{
    bottom:1rem;
  }
  50%{
    bottom:1.5rem;
  }
  100%{
    bottom:1rem;
  }
}
main h2 span::after{
  content:"";
  height:40px;
  width:3px;
  background-color:#fff;
  display:inline-block;
  animation: blink .7s ease-in-out infinite;
}
@keyframes blink {
  0%{
    opacity: 1;
  }
  100%{
    opacity: 0;
  }
}

/* about_me.css */
section{
  font-family:'Poppins', sans-serif;
  padding:5rem 0;
}
section:nth-child(2n){
  background-color:#f8f8f8;
}
section .title{
  margin-bottom:3rem;
}
section .title h4{
  font-size:1.35rem;
  color:#ed4848;
  position:relative;
}
section .title h2{
  font-size:3.5rem;
}
section .title p{
  font-size:1.15rem;
}
/* float 속성 해제 */
section .about-self::after{
  content:"";
  clear:both;
  display:block;
}
/* 본문 너비 절반 지정 & 왼쪽 배치 */
section .about-self .left{
  width:50%;
  float:left;
}
/* 이미지 크기가 부모 영역을 넘지 않도록 부모 영역의 최대 크기로 지정 */
section .about-self .left img{
  max-width:100%;
}
/* 본문 너비 절반 지정 & 오른쪽 배치 */
section .about-self .right{
  width:50%;
  float:left;
  padding:0 2rem;
}
/* 본문 오른쪽 h3 태그의 글자 크기와 여백 지정 */
section .about-self .right h3{
  font-size:2.25rem;
  margin-bottom:1rem;
}
/* 본문 오른쪽 h3 태그의 strong 태그 색상 강조 */
section .about-self .right h3 strong{
  color:#ed4848;
}
/* 본문 오른쪽 p 태그의 크기와 여백 지정 */
section .about-self .right p{
  font-size:1.15rem;
  margin:1rem 0;
}
/* 본문 오른쪽의 아이콘 폰트 크기와 여백 지정 */
section .about-self .right .social a{
  font-size:2.5rem;
  margin-right:0.2rem;
}
/* End about_me.css */
/* what_i_do.css */
/* float 속성 해제*/
section .do-me::after{
  content:"";
  display:block;
  clear:both;
}
/* 사각형 크기와 간격, 내부 여백 설정 */
section .do-me .do-inner{
  background-color:#fff;
  width:30%;
  padding:2rem;
  float:left;
  margin-right:5%;
  cursor:pointer;
}
/* 마지막 사각형의 외부 여백 설정 */
section .do-me .do-inner:last-child{
  margin-right:0;
}
/* 아이콘 폰트 크기와 색상 */
section .do-me .do-inner .icon i{
  font-size:2.5rem;
  color:#ff6a6a;
}
/* HTML5, CSS3, BootStrap v5.0 텍스트 크기와 간격 */
section .do-me .do-inner .content h3{
  font-size:2rem;
  margin:1rem 0;
}
/* 사각형 텍스트 크기 */
section .do-me .do-inner .content p{
  font-size:1.15rem;
}
/* do-inner 클래스에 마우스를 올리면 배경색과 텍스트 색상 변경 */
section .do-me .do-inner:hover{
  background-color:lightcoral;
  color:white;
}
/* do-inner 클래스에 마우스를 올리면 아이콘 폰트 색상 변경 */
section .do-me .do-inner:hover i{
  color:white;
}
/* End what_i_do.css */
/* background.css */
.bg{
  background:url('./images/background.jpg') center center;
  background-size:cover;
  background-attachment:fixed;
  height:650px;
}
/* End background.css */
/* portfolio.css */
/* clear 속성으로 float 속성값 해제*/
section.portfolio::after{
  content:"";
  display:block;
  clear:both;
}
/* portfolio-inner 사각형 꾸미기 */
section.portfolio .portfolio-inner{
  width:30%;
  margin-right:5%;
  padding:1rem 1rem 1.5rem 1rem;
  float:left;
  background-color:#f8f8f8;
  border:1px solid #ccc;
  margin-bottom:3rem;
}
/* 3번째마다 margin-right 0 적용 */
section.portfolio .portfolio-inner:nth-child(3n){
   margin-right:0;
}
/* 이미지의 크기가 부모 요소를 넘지 않도록 100%로 지정 */
section.portfolio .portfolio-inner img{
  width:100%;
  display:block;
}
/* strong 태그 색상과 간격 */
section.portfolio .portfolio-inner strong{
  color:#ff6a6a;
  margin:0.5rem 0;
  display:block;
}
/* h3 태그 색상과 간격 */
section.portfolio .portfolio-inner h3{
  font-size:1.75rem;
}
/* End portfolio.css */
/* contact_with_me.css */

section.contact .contact-me::after{
  content:"";
  display:block;
  clear:both;
}
section.contact .contact-me .left{
  width:30%;
  float:left;
}
section.contact .contact-me .right{
  float:left;
  width:65%;
  margin-left:5%;
}
section.contact .contact-me .left .card{
  border:1px solid #ccc;
  padding:1rem;
  display:flex;
  align-items:center;
  margin-bottom:1.25rem;
}
section.contact .contact-me .left .card .icon i{
  font-size:2rem;
  margin-right:15px;
}
section.contact .contact-me .right{
  float:left;
  width:65%;
  margin-left:5%;
  margin-bottom:2rem;
  border:1px solid #ccc;
  padding:1rem;
}
/* form-group 사이 간격 지정 */
section.contact .contact-me .right .form-group{
  margin-bottom:1.25rem;
}
/* label 태그가 인라인 성격이어서 외부 여백을 적용하기 위해 block으로 변경 */
section.contact .contact-me .right .form-group label{
  display:block;
  margin-bottom:0.85rem;
}
/* input 요소 꾸미기 */
section.contact .contact-me .right .form-group input{
  padding:0.625rem;
  width:100%;
  outline:none;
  border:1px solid #ccc;
  border-radius:10px;
}
/* :focus 가상 클래스 선택자로 입력 요소에 커서가 활성화되면 파란색 테두리와 그림자 효과 추가 */
section.contact .contact-me .right .form-group input:focus{
  border:1px solid #719ECE;
  box-shadow:0 0 10px #719ECE;
}
/* textarea 요소 꾸미기 */
section.contact .contact-me .right .form-group textarea{
  height:300px;
  width:100%;
  resize:none;
  border:1px solid #ccc;
  border-radius:10px;
}
/* textarea 요소에 커서 활성화가 되면 파란색 테두리와 그림자 효과 추가 */
section.contact .contact-me .right .form-group textarea:focus{
  outline:none;
  border:1px solid #719ECE;
  box-shadow:0 0 10px #719ECE;
}
/* 버튼 요소 꾸미기 */
section.contact .contact-me .right button{
  width:100%;
  padding:1rem;
  background-color:#ED4848;
  border:none;
  color:white;
}

/* End contact_with_me.css */
/* media.css */
@media screen and (max-width: 1140px){

  /* 메인 container 기준 1140 -> 992px */
  main .container{
    width: 992px;
  }

  /* 섹션 container 기준 1140 -> 600px */
  section .container{
    width:600px;
  }

  /* About me 영역 왼쪽을 너비를 50% -> 100% 변경 */
  section .about-self .left{
    width:100%;
    margin-bottom: 1.5rem;
  }
  /* About me 영역 오른쪽 너비를 50% -> 100% 변경 */
  section  .about-self .right{
    width:100%;
    padding:0;
  }

  /* What I Do 영역의 콘텐츠 박스의 너비를 30% -> 48% 변경 */
  section .do-me .do-inner{
    width:48%;
    margin-bottom: 1.5rem;
    margin-right: 0;
  }

  section .do-me .do-inner:nth-child(2n+1){
    margin-right:4%; /* 1, 3, 5...번째 본문 사각형에 margin-right 4% 적용 */
  }

  /* PortFolio 영역의 콘텐츠 박스 너비를 30% ->  48% 변경 */
  section .portfolio-me .portfolio-inner{
    width:48%;
    margin-right: 0;
  }

  section .portfolio-me .portfolio-inner:nth-child(2n+1){
    margin-right:4%;
  }

  /* Contact With Me 영역 */
  section.contact .contact-me .left{
    width:100%; /* 너비 변경 30% -> 100% */
  }

  section.contact .contact-me .right{
    width:100%;/* 너비 변경 65% -> 100% */
    margin-left: 0; /* margin 초기화 */

  }
}

@media (max-width: 992px){
  html{
    font-size: 14px;
  }

  /* 메인 영역 container 기준 너비 변경 */
  main .container{
    width: 768px; /* 992px -> 768px */
  }

  /* PortFolio 영역 */
  section .portfolio-me .portfolio-inner{
    width:100%; /* 48% -> 100% 변경 */
  }
}

@media (max-width: 768px){
  html{
    font-size: 13px;
  }

  /* 메인 영역 container 기준 너비 변경 */
  main .container{
    width: 576px; /* 768px -> 576px */
  }

  section .container{
    width:400px; /* 600px -> 400px */
  }

  section .do-me .do-inner{
    width:100%; /* 48% -> 100% */
    margin-right: 0; /* margin 초기화 */
  }
}

@media (max-width: 576px){

  html{
    font-size: 12px;
  }

  main .container{
    width: 400px; /* 576px -> 400px */
  }

  section .container{
    width:360px; /* 400px -> 360px */
  }
}

@media (max-width: 400px){

  html{
    font-size: 11px;
  }
  main .container{
    width: 320px;/* 400px -> 320px */
  }

  main h4{
    font-size: 1.5rem;
  }
  section .container{
    width: 320px;/* 360px -> 320px */
  }
  section .title h2{
    font-size: 3rem; /* 3.5rem -> 3rem */
  }
}
/* End media.css */
header.active{
  background-color:rgba(0,0,0);
  animation:fadeIn 0.5s ease-in-out;
}
@keyframes fadeIn{
  0%{
    opacity:0;
  }
  100%{
    opacity:1;
  }
}

 

 

💛2022-08-05💛

 

ex10-1.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>윈도우 열기</title>
<script>
function load(URL) {
	window.open(URL, "myWin", "left=300,top=300,width=400,height=300");
}
</script>
</head>
<body>
<h3>window.open()으로 윈도우 열기</h3>
<hr>
<a href="javascript:load('http://www.graceland.com')">
         엘비스 프레슬리 홈 페이지</a><br>
<a href="javascript:load('http://www.universalorlando.com')">
         유니버설 올랜드 홈 페이지</a><br>
<a href="javascript:load('http://www.disneyworld.com')">
         디즈니월드 홈 페이지</a><br>
</body>
</html>

 

ex10-2.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-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>

 

 

ex10-12.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>history 객체 활용</title>
</head>
<body>
<h3>history 객체 활용</h3>
<hr>
<button onclick="history.back()">back()</button>
<button onclick="history.forward()">forward()</button>
<button onclick="history.go(-1)">go(-1)</button>
</body>
</html>

 

 

+ Recent posts