전체 글 (135)

728x90

 최근까지 코딩하는 것에 대해 흥미도 잃고, 의지도 떨어지고 그러는 바람에 수업일지도 띄엄띄엄 작성하다가 마지막 공개글이 한 달 전인 것 같다. 그래서 해야지, 해야지 하고 미뤄두던 개인 프로젝트를 STS4로 해보려고 잡았다가 무엇때문인지 자꾸 에러가 나서 다 포기하고 싶어져서 그만둘 뻔 했었다.
 하지만 포기할 수는 없으니까 다시 마음잡고 모르겠으면 보고 따라하고 검색하고 그러는 것부터 차근차근 도전해보기로 했다.

나 자신, 화이팅!!!

 


 

0. 시작 전 설정(gradle, application 등)

  •  build.gradle
더보기

 해당 설정은 내가 한 것이 아니라 선생님이 수업하실 때 설정한 파일 내용을 복사해왔다.

 나중에 내가 익숙해진다면, 이것도 직접 설정해서 해보고싶다.

 

  • application.preoperties
더보기

 해당 설정은 나 혼자 검색해보면서 직접 해보려다가 에러가 계속 나는데 이유를 모르겠어서 멘붕이 왔었다.

 결국 설명들이 붙어있는 선생님이 수업하실 때 설정한 파일 내용을 복사해왔다.

 

  • log4jdbc~ / logback.xml
더보기

 해당 설정은 이해하지 못했다 ㅠ

 

 

1. dto

  • DB에 담을 회원의 정보를 담을 클래스
더보기
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Accessors(chain=true)
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MemberDto {
	private String mId;	// 아이디
	private String mName;	// 이름
	private String mEmail;	// 이메일
	private String mPw;	// 비밀번호
	private String gName;	// 게임 닉네임
	
	private String joinDate;	// 가입날짜
}
  • @Accessors(chain=true): chaining된 형태로 객체를 생성하거나 수정할 수 있다. admin 페이지를 만들거나 할 때 사용한다. (아직 잘 모르겠다. 나중에 admin 페이지를 만들어 볼 예정이라 넣어놓았다.)
  • @Builder: (아직 잘 모르겠다..)
  • @Data: getter & setter를 따로 만들 필요없이 자동으로 생성해준다.
  • @NoArgsConstructor: 기본 생성자를 만들어준다.
  • @AllArgsConstructor: 입력받은 값에 따라 생성자를 만들어준다.
  • 필드명은 파라미터명, 컬럼 명과 같아야 헷갈리지 않고 편하게 사용할 수 있다.

 

 

2. 회원가입

 2-0) 참고한 링크 ㄱ

 

회원가입 창 (현재 css가 전혀 없어서 거슬린다..테이블로라도 정렬하려고 했는데 테이블로 안 한다고 하길래 힘줘서 참는중 ㅠㅠ)

우선 뇌에 힘줘서 css는 안 넣었다.
 회원가입에서 꼭 넣어서 연습하고 싶었던 것은 비동기 통신으로 아이디 중복 검사를 하는 것이었다.
 그리고, 비밀번호 확인도 조금! 디테일하게 넣고 싶었다. (비밀번호 입력 전에 비밀번호 확인을 입력하려고 하거나 비밀번호 입력 후 비밀번호 확인을 눌렀다가 안 적는다던가 하는 그런 상황들)
 게임 관련 사이트로 할 예정이었기 때문에 인게임 닉네임도 선택 사항으로 넣고, 회원가입 창에서 취소하고 뒤로 가고싶은 경우를 위해 뒤로가기도 넣었다. (사실 뒤로가기는 인터넷에 있으니 따로 필요없을 것 같지만..!)

 

 2-1) body

  • form 태그
  • 다른 홈페이지들의 회원가입 페이지를 많이 뜯어봐야 할 것 같다. 대충 구조는 알겠는데, 이것보다 나은 구조를 짤 수 있을 것 같은데 잘 모르겠다 ㅠㅠ
  • 그리고 class가 box_tip_title인 div는 p태그로 적은 부분을 제목(선 사이에 있는)으로 해서 안에 있는 요소들을 선으로 감싸는 구조로 하고 싶었는데 찾을 수 없었다..나중에 다시 찾아봐야겠다.
더보기
<form id="join_frm" method="post" action="/member/join" onsubmit="return joinCheck()">
	<div class="big-box j-b-box">
		<div class="box_tip_title">
			<p class="tip_title">필수 입력 사항</p>
			<div class="frm_item">아이디
				<input type="text" id="mId" name="mId" class="input" placeholder="아이디 입력" value="" maxlength="20" autocapitalize="off">
				<div id="chId" style="display: none;"></div>
			</div>
			<div class="frm_item">이름
				<input type="text" id="mName" name="mName" class="input" placeholder="이름 입력" value="" maxlength="10" autocapitalize="off">
			</div>
			<div class="frm_item">이메일
				<input type="text" id="mEmail" name="mEmail" class="input" placeholder="이메일 입력" value="" maxlength="40" autocapitalize="off">
			</div>
			<div class="frm_item" id="joinPwDiv">
				비밀번호
				<input type="password" id="mPw" name="mPw" class="input" placeholder="비밀번호 입력" value="" maxlength="20">
				<br>비밀번호 확인
				<input type="password" id="chMPw" name="chMPw" class="input" placeholder="비밀번호 재입력" value="" maxlength="20">
				<div id="chPw" style="display: none;"></div>
			</div>
		</div>
		<div class="box_tip_title">
			<p class="tip_title">선택 입력 사항</p>
			<div class="frm_item">인게임 닉네임
				<input type="text" id="joinMGName" name="joinMGName" class="input" placeholder="인게임 닉네임 입력" value="" maxlength="40" autocapitalize="off">
			</div>
		</div>
	</div>
	<br>
	<input type="button" value="뒤로가기" onclick="history.back()">
	<button type="submit" class="btn btn-3 btn-3e" id="joinSubBtn" style="text-align: center;">join the membership!</button>
</form>

 

 2-2) js

더보기
let useId = false;	// id 체크용
let usePw = false;	// pw 체크용
  • jquery를 여럿으로 나누어 작성했기 때문에 나중에 회원가입 버튼을 눌렀을 때 간편하게 확인하기 위해 필드에 boolean으로 선언해두었다.

 

$('#mId').on('keyup blur',function(){		// 중복 아이디 체크
	let id = $('#mId').val();
	document.getElementById("chId").style.display = 'block';
	if (id==''){
		$('#chId').html('아이디를 입력해주세요.').css('color','red');
		$('#mId').focus();
		return;
	}
	let chIdSend = {mId:id};
	console.log("chIdSend: ",chIdSend);
	$.ajax({
		method:'get',
		url: '/member/idCheck',
		data: chIdSend,
	}).done(function(res){
		console.log("res: ",res);
		if(res=='ok'){
			$('#chId').html('아이디 사용 가능!').css('color','blue');
			useId = true;
		}else{
			$('#chId').html('아이디 사용 불가!').css('color','red');
			useId = false;
		}
		
	}).fail((err,status)=>{
	console.log("err:", err);
	console.log("status:", status);
	useId=false;
	})
});
  • 중복 아이디를 ajax 비동기로 통신하기 위한 코드
  • jquery 이벤트로 keyup(키를 누르고 뗄 때 실행), blur(입력 양식에서 마우스 커서가 떼어지면 실행) 두 개를 동시에 사용했다.
  • 비동기 통신을 하기 전에 blur를 통해 회원가입 할 아이디 값이 빈 칸이라면 아이디 칸에 커서를 옮기고 return하도록 했다.
  • return되지 않았다면 비동기 통신을 위해 ajax 구조를 입력했다.
  • 첫번째 괄호, 대괄호에는 method(보낼 방법: get/post), url(보낼 위치), data(보낼 데이터)를 입력한다.
  • 뒤에 오는 두번째 코드는 갖다 오는 것에 성공하면 실행할 코드로, 받아온 데이터(매개변수)에 따라 아이디가 사용가능한지 아닌지 input mId 밑에 있는 div안 글씨를 바꾼다.
  • 실패 시 세번째 코드가 받는다.

 

$('#chMPw').on('click',function(){	// 비밀번호 체크
	let pw = $('#mPw').val();
	let chPw = $('#chMPw').val();
	let con = document.getElementById("chPw");
	con.style.display = 'block';
	if (pw==''){
		$('#chPw').html("비밀번호를 먼저 입력해주세요.").css("color",'red');
		$('#mPw').focus();
		return;
	}
})
$('#chMPw').blur(function(){
	let pw = $('#mPw').val();
	let chPw = $('#chMPw').val();
	let con = document.getElementById("chPw");
	con.style.display = 'block';
	if (pw!='' && chPw==''){
		$('#chPw').html("비밀번호 확인 칸은 비워둘 수 없습니다.").css("color",'red');
		$('#chMPw').focus();
		return;
	}
})
$('#joinPwDiv').on('keyup', function(){
	let pw = $('#mPw').val();
	let chPw = $('#chMPw').val();
	let con = document.getElementById("chPw");
	con.style.display = 'block';
	if (pw!=''){
		if(pw.length<=20 && pw.length>=8){
			$('#chPw').html("");
		}else if(pw.length>20 || pw.length<8){
			$('#chPw').html("비밀번호의 길이는 8~20로 정해주세요.").css("color",'red');
			$('#mPw').focus();
			return;
		}
		if(chPw!='' && pw!=chPw){
			$('#chPw').html("비밀번호가 다릅니다.").css("color",'red');
			$('#chMPw').focus();
		}else if(pw==chPw){
			usePw = true;
			con.style.display = 'none';
		}
			return;
	}
	usePw = false;
});
  • 첫번째 코드는 비밀번호 확인 칸을 클릭했을 때 비밀번호 칸이 비워져있다면 비밀번호 칸에 커서를 옮긴다.
  • 두번째 코드는 비밀번호 확인 칸을 클릭했다가 빈 칸인 상태(채웠다가 지운 경우도)에서 다른 곳을 클릭 시 비밀번호 확인 칸을 비울 수 없다며 비밀번호 확인 칸에 커서를 옮긴다.
  • 세번째 코드는 비밀번호/비밀번호 확인 칸에서 키보드가 눌렸다가 떼어질 때 비밀번호 칸의 길이, 비밀번호 칸과 비밀번호 확인 칸의 동일값인지 확인한다.

 

function joinCheck(){
	let name = $('#mName').val();
	let email = $('#mEmail').val();
	let pw = $('#mPw').val();
	let chPw = $('#chMPw').val();
	let gName = $('#mGName').val();
	
	if (!useId){
		alert("아이디를 확인해주세요.");
		$('#mId').focus();
		return false;
	}else if(name==''){
		alert("이름을 입력해주세요.");
		$('#mName').focus();
		return false;
	}else if(email==''){
		alert("이메일을 입력해주세요.");
		$('#mEmail').focus();
		return false;
	}else if(!usePw){
		alert("비밀번호를 확인해주세요.");
		$('#mPw').focus();
		return false;
	}
	alert("회원가입 성공!")
	return true;
}
  • 모든 칸의 값을 저장해두고, 조건에 따라 커서를 움직이고 리턴한다.
  • 모든 조건에 해당하지 않는다면 회원가입 성공 알림창을 띄우고 form 안의 정보들을 전송한다. 

 

 2-3) controller

더보기
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.myPro.persP.service.MemberService;
import lombok.extern.slf4j.Slf4j;

@RestController		// asynchronous(비동기) 를 받아주는 컨트롤러
@Slf4j
public class MemberAsyController {
	@Autowired
	private MemberService mSer;
	
	@GetMapping("/member/idCheck")
	public String idCheck(@RequestParam(name = "mId") String mId) {
		System.out.println(mId);
		log.info("==> GetMapping - idCheck 요청: ", mId," <==");
		return mSer.idCheck(mId);
	}
}
  • ajax 비동기 통신을 위해 만든 MemberAsyController
  • @RestController는 asynchronous(비동기)를 받아주는 컨트롤러다.
  • 가져올 매개변수에 @RequestParam에 mId(가져올 값의 키?)를 적어주지 않으면 에러가 나며 비동기 통신에 실패한다.
  • MemberService에 매개변수를 넣어 idCheck 메소드를 실행해 리턴 값을 그대로 리턴해준다.

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.myPro.persP.dto.MemberDto;
import com.myPro.persP.service.MemberService;

import lombok.extern.slf4j.Slf4j;

@Controller
@Slf4j
public class MemberController {
	@Autowired
	private MemberService mSer;
	
	@GetMapping("/member/joinfrm")
	public String join() {
		log.info("==> GetMapping - joinfrm 요청 <==");
		return "join";
	}
	
	@PostMapping("/member/join")
	public String join(MemberDto mDto, RedirectAttributes ra) {
		boolean result = mSer.join(mDto);
		if(result) {
			ra.addFlashAttribute("msg","회원가입 성공!");
			return "redirect:/member/loginfrm";
		}
		ra.addFlashAttribute("msg","회원가입 실패");
		return "redirect:/";
	}
	
	@GetMapping("/member/loginfrm")
	public String login() {
		log.info("==> GetMapping - loginfrm 요청 <==");
		return "login";
	}
	@PostMapping("/member/login")
	public String logrin() {
		return "login";
	}
}
  • MemberController
  • login은 아무 기능 없이 임시로 만들어두었다.
  • GetMapping으로 joinfrm을 요청하는 것은 메인 화면에서 들어오는 링크로, join.jsp를 리턴해준다.
  • PostMapping이 진정한 회원가입을 위한 기능인데, 여기서 메시지를 저장했는데 사용하는 것을 잊었다..
  • form 태그에서 보내온 데이터를 알아서 MemberDto로 저장하고, 이 mDto를 MemberService를 통해 boolean으로 회원가입(DB전송) 성공여부를 받고, 성공여부에 따라 보낼 위치를 따로 지정해 리턴한다.

 

 2-4) service

더보기
@Autowired
private MemberDao mDao;

 

public boolean join(MemberDto mDto) {
	BCryptPasswordEncoder pwEn = new BCryptPasswordEncoder();
	mDto.setMPw(pwEn.encode(mDto.getMPw()));
	
	return mDao.join(mDto);
}
  • 회원가입을 위한 메소드
  • BcryptPasswordEncoder를 통해 비밀번호를 암호화해주고, MemberDao의 join을 실행하고 리턴 값을 그대로 리턴해준다.

 

public String idCheck(String mId) {
	log.info("===> mSer checkId 요청: ",mId," <===");
	boolean result = mDao.idCheck(mId);
	System.out.println("==== mSer -> result: "+result);
	if(!result) {
		return "ok";
	}
	return "no";
}
  • 중복 아이디 체크를 위한 메소드
  • MemberDao에 id 검색을 실행하고 성공 값을 boolean으로 받아, 실패, 성공 시에 따라 "ok",  "no"를 리턴해준다.

 

 2-5) dao

더보기
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import com.myPro.persP.dto.MemberDto;

@Mapper
public interface MemberDao {
	boolean join(MemberDto mDto);
	
	boolean idCheck(String mId);
}
  • MemberDao

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.myPro.persP.dao.MemberDao">
	<insert id="join" parameterType="MemberDto">
		insert into member values(#{mId},#{mName},#{mEmail},#{mPw},#{gName},default)
	</insert>
	
	<select id="idCheck" parameterType="String" resultType="boolean">
		select count(*) from member where mId=#{mId}
	</select>
	
</mapper>
  • MemberDao의 xml 파일 (mappers)
  • MemberDao.java의 이름이 id값이 되고, parameterType은 받아올 타입이다. 받아올 타입은 알아서 인식할 수 있기 때문에 생략해도 된다.
  • resultType은 리턴해줄 타입이다. 안 적어도 java 파일의 타입을 통해 알아서 인식할 수도 있다. (생략하는 것을 추천하지 않는다고 하셨던 것 같다.)

 

 

3. 결과? 스크린샷 화면들

더보기
  • 아이디에 아무것도 입력하지 않고, 다른 곳을 클릭했을 경우

 

  • 아이디를 사용할 수 있을 경우

 

  • 아이디를 사용할 수 없는 경우

 

  • 이름, 이메일 입력 없이 회원가입 버튼을 눌렀을 경우

 

  • 비밀번호 입력 없이 비밀번호 확인 칸을 클릭했을 경우

 

  • 비밀번호 길이가 부족하거나 넘었을 경우

* 이때 길이를 충족하지 않은 상태로 비밀번호 확인 칸 입력 시 비밀번호 칸으로 이동한다.

 

  • 비밀번호가 다를 경우

 

  • 비밀번호가 같은 경우

 

  • 회원가입 성공!

* DB 확인

1, 3번은 이전에 실험용으로 넣은 데이터다.

2번이 막 일지를 정리하면서 넣은 데이터!

 


 

틀리거나 헷갈렸던 점 메모

  • ajax
  • js에서 display (none, block) 제어

 


 

전체 피드백

  • 타임리프 안 쓸건데 처음 시작 때 타임리프 넣어서 에러나고 제이쿼리 링크 안 긁어와서 제이쿼리 안 먹고 정말 다사다난했다 ㅠㅠ
  • sql 구문에서도 resultType을 parameterType으로 적어놓고 뭐가 문젠지 모르고, 매개변수도 #${mId} 이런 식으로 적어놓고 에러나야 알고 그랬다.
  • 역시 해봐야 익숙해지는 것 같다. 빨리 이거 끝내고 여러개 더 만들어봐야겠다. 비슷하더라도 여러번 해봐야 익숙해져서 나중에는 if문, for문 익숙해지는 것 마냥 편하게 사용할 테니까..!
  • 그래도 뭔가 해결되니까 그나마 하고싶어지는 마음은 생기는 것 같다! 슬럼프(?) 극복하기..!

 


 

 

728x90
728x90

 

수업내용 정리 (Eclipse)

 

선생님이 과제로 관리자로 로그인하면 회원 목록+회원 정보를 띄우고, 일반 회원으로 로그인하면 로그인 한 회원 정보를 띄우는 것을 내주셔서 밑의 코드가 불완전하다.

 

1. wepapp

  • WEB-INF (jsp 넣는 공간 아님!!!!!!!)

 

  • jsp ㄱ 
더보기
  • index
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>index.html - 시작 페이지</h1>
	<a href="loginfrm">로그인</a>
	<a href="joinfrm">회원가입</a>
	<c:if test="${1222<2}"> 1보다 2가 크다.</c:if>
</body>
</html>

 

  • joinFrm
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	let m = '${msg}'
	if (m != '') {
		alert(m);
	}
</script>
</head>
<body>
	<h1>joinFrm.jsp - 회원가입 양식</h1>
	<form action="join" method="post" name="joinfrm">
		<table>
			<tr>
				<td>아이디</td>
				<td><input type="text" name="id"></td>
			</tr>
			<tr>
				<td>비밀번호</td>
				<td><input type="password" name="pw"></td>
			</tr>
			<tr>
				<td>이름</td>
				<td><input type="text" name="name"></td>
			</tr>
			<tr>
				<td>성별</td>
				<td align="center"><input type="radio" name="gender" value="남자">남자
					&nbsp; <input type="radio" name="gender" value="여자">여자</td>
			</tr>
			<tr align="right">
				<td colspan="2"><button>회원가입</button>&nbsp;
					<button type="reset">취소</button></td>
			</tr>
		</table>
	</form>
</body>
</html>

 

  • loginFrm
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>loginFrm.jsp - 로그인 화면</h1>
	<form action="login" method="post">
		<table>
			<tr>
				<td>아이디</td>
				<td><input type="text" name="id"></td>
			</tr>
			<tr>
				<td>비밀번호</td>
				<td><input type="password" name="pw"></td>
			</tr>
			<tr align="right">
				<td colspan="2"><button>로그인</button></td>
			</tr>
		</table>
	</form>
	<form action="joinfrm" method="post">
		<button>회원가입</button>
	</form>
</body>
</html>

 

  • main
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	let m = '${msg}'
	if (m != '') {
		alert(m);
	}
</script>
</head>
<body>
	<h1>main.jsp - 메인 화면</h1>
	<table>
		<tr>
			<td colspan="2">${accessResult}</td>
		</tr>
		<tr>
			<td colspan="2" align="right">${logout}</td>
		</tr>
	</table>
</body>
</html>

 

  • memberList
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>
	console.log('${mList}');
</script>
</head>
<body>
	<h1>memberList.jsp</h1>
	<table>
		<tr>
			<th colspan="2">회원 목록</th>
		</tr>
		<tr>
			<td>회원 아이디</td>
			<td>삭제</td>
		</tr>
		<tr>
			<td></td>
			<td></td>
		</tr>
	</table>
</body>
</html>

 

 

2. Java - controller

  • HomeContoller
package controller;

import java.io.IOException;

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

import common.Forward;
import service.MemberMM;
import service.MovingPage;

@WebServlet({"/login","/loginfrm","/joinfrm","/join","/logout","/main", "/memberlist", "/memberinfo"})
public class HomeContoller extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		String cmd=request.getServletPath();
		System.out.println("cmd="+cmd);
		//회원관리 서비스클래스
		MemberMM mm=new MemberMM(request,response);
		//게시판관리 서비스클래스
		MovingPage mp=new MovingPage(request,response);
		
		Forward fw=null;
		if(cmd.equals("/loginfrm")) {
			fw=mp.showLoginFrm();			
		}else if(cmd.equals("/login")) {
			fw=mm.login();
		}else if(cmd.equals("/logout")) {
			fw=mm.logout();
		}else if(cmd.equals("/joinfrm")) {
			fw=mp.showJoinFrm();
		}else if(cmd.equals("/join")) {
			fw=mm.join();
		}else if(cmd.equals("/memberlist")) {
			fw=mm.getMemberlist();
		}else if(cmd.equals("/memberinfo")) {
			fw=mm.getMemberinfo();
		}
		
		if(fw!=null) {
			if(fw.isRedirect()) { //true: redirect
				response.sendRedirect(fw.getPath()); // 새로운 req, res 객체 생성 + 주소창 새 url 생성
			}else {
				request.getRequestDispatcher(fw.getPath()).forward(request, response); // 기존 req, res 객체 사용 + 주소창 갱신X
			}
		}
	}
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

 

 

3. Java - service (MP, MM)

더보기
  • MovingPage (MP)
package service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import common.Forward;

public class MovingPage {
	HttpServletRequest request;
	HttpServletResponse response;

	public MovingPage(HttpServletRequest request, HttpServletResponse response) {
		this.request = request;
		this.response = response;
	}

	public Forward showLoginFrm() {
		Forward fw = new Forward();
		// 로그인여부 판단
		if (request.getSession().getAttribute("id") != null) {
			fw.setPath("main.jsp");
			fw.setRedirect(true);
		} else {
			fw.setPath("loginFrm.jsp");
			fw.setRedirect(true);
		}
		return fw;
	}

	public Forward showJoinFrm() {
		Forward fw = new Forward();
		// 로그인여부 판단
		if (request.getSession().getAttribute("id") != null) {
			fw.setPath("main.jsp");
			fw.setRedirect(true);
		} else {
			fw.setPath("joinFrm.jsp");
			fw.setRedirect(true);
		}
		return fw;
	}

}

 

  • MemberMM (MM)
package service;

import java.util.ArrayList;
import java.util.HashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import common.Forward;
import dao.MemberDao;

public class MemberMM {
	HttpServletRequest request;
	HttpServletResponse response;

	public MemberMM(HttpServletRequest request, HttpServletResponse response) {
		this.request = request;
		this.response = response;
	}

	public Forward login() {
		String id = request.getParameter("id");
		String pw = request.getParameter("pw");
		MemberDao mDao = new MemberDao();
		Forward fw = new Forward();
		HttpSession session = request.getSession();
		HashMap<String, String> hMap = new HashMap<>();
		hMap.put("id", id);
		hMap.put("pw", pw);
		if (mDao.login(hMap)) {
			session.setAttribute("id", id);
			;
			session.setAttribute("logout", makeLogoutHtml());
			session.setAttribute("accessResult", makeResultHtml());
			request.setAttribute("msg", "로그인 성공");
			fw.setPath("main.jsp");
			fw.setRedirect(true);
		} else {
			request.setAttribute("msg", "로그인 실패");
			fw.setPath("loginFrm.jsp");
			fw.setRedirect(false);
		}
		mDao.close();
		return fw;
	}

	private String makeLogoutHtml() {
		StringBuffer sb = new StringBuffer();
		sb.append("<div>");
		sb.append("<a href='logout'>로그아웃");
		sb.append("</div>");
		return sb.toString();
	}

	private String makeResultHtml() {
		// 관리자: admin /////// 임의의 아이디에 권한 1, 0 으로 판단
		StringBuilder sb = new StringBuilder();
		String id = request.getSession().getAttribute("id").toString();
		if (id.equals("admin")) {
			sb.append("<a href='/memberlist'>(관리자)회원목록</a>");
		} else {
			sb.append("<a href='/memberinfo?id=" + id + "'>내 정보</a>");
		}
		return sb.toString();
	}

	public Forward logout() {
		request.getSession().invalidate();
		Forward fw = new Forward();
		fw.setPath("./"); // index.jsp
		fw.setRedirect(true);
		return fw;
	}

	public Forward join() {
		// 비지니스(업무) 로직
		// Dao: Data Access Object
		String id = request.getParameter("id");
		String pw = request.getParameter("pw");
		String name = request.getParameter("name");
		String gender = request.getParameter("gender");
		System.out.printf("%s,%s,%s,%s\n", id, pw, name, gender);
		// Member Bean or HashMap<k,v>
		HashMap<String, String> hMap = new HashMap<>();
		hMap.put("id", id);
		hMap.put("pw", pw);
		hMap.put("name", name);
		hMap.put("gender", gender);

		MemberDao mDao = new MemberDao(); // db접속
		boolean result;
		result = mDao.join(hMap); // db 로직-->-->insert작업--->
		mDao.close();
		Forward fw = new Forward();
		if (result) {
			System.out.println("회원가입 성공");
			request.setAttribute("msg", "회원가입성공");
			fw.setPath("loginFrm.jsp");
			fw.setRedirect(true);
		} else {
			// System.out.println("회원가입 실패");
			request.setAttribute("msg", "회원가입실패");
			fw.setPath("joinFrm.jsp");
			fw.setRedirect(false);
		}
		return fw;
	}

	public Forward getMemberlist() throws JsonProcessingException {
		MemberDao mDao = new MemberDao();
		ArrayList<String> mList = mDao.getMemberList();
		mDao.close();
		Forward fw = new Forward();
		if (mList != null) {
			// 1.makeHtml 으로 반복문?
			// 2.javaScript 로 반복문? <<- java 객체를 json 으로 변환
			// 3.jstl 으로 반복문?
			ObjectMapper om = new ObjectMapper();
			// / java 객체 -->> json 변환
			String json = om.writeValueAsString(mList);
			System.out.println("json: " + json);
			request.setAttribute("mList", json);
			fw.setPath("memberList.jsp");
			fw.setRedirect(false);
		} else {
			fw.setPath("main.jsp");
			fw.setRedirect(true);
		}
		return fw;
	}

	public Forward getMemberinfo() {
		return null;
	}

}

 

 

4. Java - dao

package dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

import common.JdbcUtil;

public class MemberDao {
	Connection con;
	PreparedStatement pstmt;
	ResultSet rs;

	public MemberDao() {
		// db 접속
		con = JdbcUtil.getConnection();
	}

	public boolean join(HashMap<String, String> hMap) {
		String sql = """
				insert into member(id,pw,name,gender)
				 value(?,?,?,?)
				""";
		int result = 0;
		try {
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, hMap.get("id"));
			pstmt.setString(2, hMap.get("pw"));
			pstmt.setString(3, hMap.get("name"));
			pstmt.setString(4, hMap.get("gender"));
			result = pstmt.executeUpdate();
			if (result > 0) {
				System.out.println("DB 회원가입 성공");
				return true;
			} else {
				System.out.println("DB 회원가입 성공");
				return false;
			}
		} catch (SQLException e) {
			System.out.println("join 예외 발생");
			e.printStackTrace();
			return false;
		}
	}

	public void close() {

	}

	public boolean login(HashMap<String, String> hMap) { // login 구문
		String sql = "select * from member where id =? ";
		try {
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, hMap.get("id"));
			rs = pstmt.executeQuery();
			if (rs.next()) {
				// 아이디 일치
				if (rs.getString("pw").equals(hMap.get("pw"))) {
					return true;
					// 비번 일치
				}
			}
		} catch (SQLException e) {
			System.out.println("dao login 예외 발생");
			e.printStackTrace();
		}
		return false;
	}

	public ArrayList<String> getMemberList() {
		ArrayList<String> mList = null;
		String sql = "select id from member";
		try {
			pstmt = con.prepareStatement(sql);
			rs = pstmt.executeQuery();
			mList = new ArrayList<>();
			while (rs.next()) {
				mList.add(rs.getString("id"));
			}
		} catch (SQLException e) {
			System.out.println("dao memberList 예외");
			e.printStackTrace();
		}
		return mList;
	}
}

 

5. Java - common (Forward, JdbcUtil - 이전에 쓰던 것들 복사)

더보기
  • Forward
package common;

//포워딩 정보
public class Forward {
	// true: redirect포워딩
	// false: (dispatcher)포워딩
	private boolean isRedirect; // false
	private String path; // 포워딩할 뷰 페이지 or url

	public boolean isRedirect() {
		return isRedirect;
	}

	public void setRedirect(boolean isRedirect) {
		this.isRedirect = isRedirect;
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

}

 

  • JdbcUtil
package common;

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

public class JdbcUtil {
	static {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			System.out.println("드라이버 로딩 성공");
		} catch (ClassNotFoundException e) {
			System.out.println("드라이버 로딩 실패");
			e.printStackTrace();
		}
	}

	public static Connection getConnection() {
		try {
			Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/workdb", "icia", "1234");
			System.out.println("db 접속 성공");
			return con;
		} catch (SQLException e) {
			System.out.println("db 접속 실패");
			e.printStackTrace();
		}
		return null;
	}

	public static void dbClose(ResultSet rs, PreparedStatement pstmt, Connection con) {
		try {
			if (rs != null)
				rs.close();
			if (pstmt != null)
				pstmt.close();
			if (con != null)
				con.close();
			System.out.println("db연결 종료 성공");
		} catch (SQLException e) {
			System.out.println("db연결 종료 실패");
			e.printStackTrace();
		}
	}

	public static void dbCommit(Connection con) {
		try {
			con.commit();
		} catch (SQLException e) {
			System.out.println("commit fail");
			e.printStackTrace();
		}
	}

	public static void dbRollback(Connection con) {
		try {
			con.rollback();
		} catch (SQLException e) {
			System.out.println("rollback fail");
			e.printStackTrace();
		}
	}
}

 


 

전체 피드백

  • 또 고작 '/' 이 작대기 하나 까먹었다고 오류가 나서 켜지질 않았다. 조장님(특: 옆자리)이랑 열심히 찾다가 먼저 찾으셔서 알려주셨는데 너무 허망했다..

 


728x90
728x90

 

수업내용 정리 (VSCode) - 회원가입 페이지

 

로그인 관련으로 페이지 만드는 것을 팀플로 시키셔서 로그인, 회원가입, 아이디/비번 찾기, 로그인 성공 시 main에서 확인 기능 등으로 작업을 나눠서 하기로 했는데 그 중 나는 회원가입을 맡았다.

DB 연동은 하지 않기 때문에 localStorage(로컬 스토리지)에 저장하는 방식으로 이용했다.
우선 css는 확정된 것이 아니기 때문에 빼놓고 정리했다.

 

0. 미리보기

  • css 있는 버전
더보기
예시로 입혀둔 css는 로그인을 맡은 팀원의 css를 따랐다.
입력 전
입력 후

 

  • css 없는 버전
더보기
입력 전
입력 후

 

 

1. html

    <div id="join">
        <h3>Join</h3>
        <form id="joinForm" name="joinForm" method="post">
            <label for="joinId"></label> <b>ID</b>
            <button type="button" id="joinIdCh">&ensp;ID 중복 확인&ensp;</button> <br>
            <input type="text" name="joinId" id="joinId" placeholder="아이디 입력" required> <br>

            <label for="joinName"></label> <b>NAME</b> <br>
            <input type="text" name="joinName" id="joinName" placeholder="이름 입력" required> <br>

            <label for="joinPw"></label> <b>PASSWORD</b> <br>
            <input type="password" name="joinPw" id="joinPw" placeholder="비밀번호 입력" required> <br>

            <label for="checkPw"></label> <b>CHECK PASSWORD</b> <br>
            <input type="password" name="checkPw" id="checkPw" placeholder="비밀번호 재입력" required>
            <p id="chPwP"></p> <br>
            <input type="button" value="회원가입" id="joinButton"> <br>
        </form>
    </div>
  • id는 회원가입이니까 예외 경우를 제외하고는 모두 join을 붙여 작성했다.
  • 가장 큰 박스로 div를 만들어서 h3와 form을 집어넣었다.
  • form 요소 ㄱ
더보기
  • ID
            <label for="joinId"></label> <b>ID</b>
            <button type="button" id="joinIdCh">&ensp;ID 중복 확인&ensp;</button> <br>
            <input type="text" name="joinId" id="joinId" placeholder="아이디 입력" required> <br>
  • ID는 중복 될 수 없도록 했기 때문에 중복인지 확인할 수 있도록 하기 위해 버튼을 만들었다.
  • &ensp;는 띄어쓰기를 두 번 주어 공간을 주고 싶었기 때문에 양 끝에 집어넣었다.
  • 사용자가 입력할 수 있는 칸인 input:text에는 placeholder 속성을 넣어 "아이디 입력"이라는 안내 문구를 작성했다.

 

 

  • NAME
            <label for="joinName"></label> <b>NAME</b> <br>
            <input type="text" name="joinName" id="joinName" placeholder="이름 입력" required> <br>
  •  ID와 동일하게 placeholder 속성으로 "이름 입력"이라는 안내 문구를 작성했다.

 

 

  • PW
            <label for="joinPw"></label> <b>PASSWORD</b> <br>
            <input type="password" name="joinPw" id="joinPw" placeholder="비밀번호 입력" required> <br>

            <label for="checkPw"></label> <b>CHECK PASSWORD</b> <br>
            <input type="password" name="checkPw" id="checkPw" placeholder="비밀번호 재입력" required>
            <p id="chPwP"></p> <br>
  • 비밀번호와 비밀번호 확인용 칸에도 placeholder 속성으로 각 각 안내 문구를 작성했다.
  • 마지막 줄의 p요소(id="chPwp")는 joinPw와 checkPw를 대조했을 때, 문구를 출력하려고 만들었다.
  • 길이나 문자열에 따로 제한을 두진 않았다.

 

  • JOIN BUTTON
            <input type="button" value="회원가입" id="joinButton"> <br>
  • 위 ID, NAME, PW 항목이 모두 작성하고 가입할 수 있는 버튼을 만들었다. jquery 함수를 사용할 것이기 때문에 onclick은 사용하지 않았다.

 

 

2. js

  • 우선 id 중복 체크를 했는지 확인하기 위해 전역 변수를 하나 선언했다.
        var idch = false;

 

  • 회원가입 ㄱ 
더보기
        $('#joinButton').click(function () {
            let id = document.getElementById('joinId').value;
            let name = document.getElementById('joinName').value;
            let pw = document.getElementById('joinPw').value;
            let chPw = document.getElementById('checkPw').value;
            if (id == "") {
                // 아이디 공란 체크
                alert('아이디를 입력해주세요.')
                $('#joinId').focus();
                return false;
            } else if (idch == false) {
                // 아이디 중복 체크
                alert('아이디 중복 체크를 해주세요.')
                $('#joinIdch').focus();
                return false;
            } else if (name == "") {
                // 이름 공란 체크
                alert('이름을 입력해주세요.')
                $('#joinName').focus();
                return false;
            } else if (pw == "") {
                // 비밀번호 공란 체크
                alert('비밀번호를 입력해주세요.')
                $('#joinPw').focus();
                return false;
            } else if (chPw == "") {
                // 비밀번호 재입력 공란 체크
                alert('비밀번호 재입력을 확인해주세요.')
                $('#checkPw').focus();
                return false;
            } else if(pw==chPw){
                // 비밀번호 일치 체크
                $('#chPwP').html('비밀번호가 일치하지 않습니다.');
            }

            let userInfo = {
                id: id,
                name: name,
                pw: pw
            }
            localStorage.setItem(id, JSON.stringify(userInfo))
            alert('회원가입 성공!')
        });
  • joinButton 버튼 클릭 시 함수 호출
  • joinId, joinName, joinPw, checkPw의 값을 가져와서 각 변수에 담아놨다.
  • 그리고 변수가 비어있으면 아이디부터 차례로 입력해달라는 메세지를 띄우고 커서를 비어있는 칸으로 이동하도록 했다.
  • 아이디 중복 체크 및 비밀번호 일치 체크까지 하고 나면 배열 변수를 하나 만들어 localStorage에 id를 키로 주고, 배열을 값으로 해서 정보를 저장하도록 했다.
  • 정보 저장에 성공하면 회원가입 성공 메세지를 띄웠다.

 

  • 중복 아이디 체크 ㄱ 
더보기
        $('#joinIdCh').click(function () {
            let duplicateId = document.getElementById('joinId').value;
            if (duplicateId == "") {
                // 아이디 공란 체크
                alert('아이디를 입력해주세요.')
                $('#joinId').focus();
                return false;
            }

            let localInfo = localStorage.getItem(duplicateId)
            if (localInfo == null) {
                idch = true
                alert('아이디 사용 가능!')
            } else {
                alert('아이디가 중복됩니다.')
                $('#joinId').focus();
            }
        })
  • joinIdCh 버튼 클릭 시 함수 호출
  • joinId에서 값을 가져와서 값이 있는지 체크하고, 없으면 joinId에 커서가 이동하도록 했다.
  • joinId에 값이 있다면 localStorage에 joinId의 값에 해당하는 배열을 찾아 가져온다.

 

  • 배열이 있다면 idch의 값을 true로 바꾸고 아이디 사용 가능 메시지를 띄운다.
  • 배열이 비어있다면 아이디가 중복된다는 메시지를 띄우고, joinId에 커서가 이동하도록 했다.

 

  • 비밀번호 일치 체크 ㄱ 
더보기
        $('#checkPw').keyup(function () {
            let pw = document.getElementById('joinPw').value;
            let chPw = document.getElementById('checkPw').value;
            if (pw == "") {
                $('#chPwP').html('비밀번호를 입력해주세요.');
            } else if (pw != chPw) {
                $('#chPwP').html('비밀번호가 일치하지 않습니다.');
            } else {
                $('#chPwP').html('비밀번호 일치');
            }
        })
  • chekPw에 값이 입력되면 함수 호출
  • joinPw, checkPw의 값을 가져와 변수에 저장해두고 joinPw가 비어있을 경우, 비밀번호를 입력하라는 메시지를 띄운다.
  • joinPw에 값이 있을 경우, checkPw와 값을 비교하고 다르면 일치하지 않다는 메시지를 띄운다.
  • 같으면 비밀번호가 일치한다는 메시지를 띄운다.

 

  • 비밀번호 재입력부터 값이 채워져있을 경우 ㄱ 
더보기
        $('#joinPw').keyup(function () {
            let pw = document.getElementById('joinPw').value;
            let chPw = document.getElementById('checkPw').value;
            if (chPw != "" && chPw != pw) {
                $('#chPwP').html('비밀번호가 일치하지 않습니다.');
            } else if(chPw != "" && chPw == pw) {
                $('#chPwP').html('비밀번호 일치');
            }
        })
  • joinPw에 값이 입력되면 함수 호출
  • joinPw, checkPw의 값을 변수에 저장해두고, checkPw가 값이 있고, joinPw와 비교했을 때 다르면 일치하지 않다는 메시지를 띄운다.
  • 값이 같다면 일치한다는 메시지를 띄운다.

 

  • input 전부 값이 채워지면 색 채우고 값이 빠지면 다시 색 빼기 ㄱ 
더보기
        $('#join').keyup(function () {
            let id = document.getElementById('joinId').value;
            let name = document.getElementById('joinName').value;
            let pw = document.getElementById('joinPw').value;
            let chPw = document.getElementById('checkPw').value;
            if (id != "" && name != "" && pw != "" && chPw != "") {
                $('#joinButton').css('background-color', '#6A24FE').css('color', '#fff')
            } else {
                $('#joinButton').css('background-color', '#F8F8F8').css('color', '#000')
            }
        })
  • join에 값이 입력되면 함수를 호출
  • 든 값을 체크해야 하기 때문에 div를 이용했다.
  • joinId, joinName, joinPw, checkPw의 값을 가져와서 각 변수에 담아놨다.
  • 각 변수들이 공란이 아닐 경우 joinButton의 배경색과 글자색을 #6A24FE, #ffffff로 변경했다.
  • 아닐 경우, #f8f8f8, #000000으로 변경했다.

 


 

전체 피드백

  • 빈 칸인 상태로 내가 생각해내려고 하니 앞이 캄캄했다. 빨리 css를 집어넣고 싶어서 그것 때문에 더 우왕좌왕한 것도 있었던 것 같다. 생각나는(하고싶은) 것은 대충 메모장에 적어두거나 하고 하나에만 집중하기!!
  • 안 익숙해서 어쩔 수 없이 거의 검색을 해가면서 한 것 같다. 빨리 익숙해지려면 다른 페이지도 만들어보고 그래야겠다..
  • 나도 잘은 모르지만 이것저것 해보고 그러다 어쩌다보니 다른 사람에게 조금 도움이 된 것 같다! 다행! (+도움이 되지 못했던 것은 집에 와서 한가지 해결해서 월요일에 가서 알려줘야겠다.)
  • 40일차는 병결, 41일차는 조퇴로 인해 수업일지를 작성하지 못했다. 건강관리 잘하기..!

 


728x90
728x90

 

수업내용 정리 (VSCode - JS)

 

1. Json

  <script>
    const user = {
      name: 'kim',
      age: 30,
      emails: ['thekim@gmail.com', 'neo@naver.com']
    }
    console.log(user)

    // const str=JSON.stringify(user)
    // console.log('str', str);
    // console.log(typeof str);
    // const obj=JSON.parse(str)
    // console.log('obj', obj);
    //개발자도구 application
    //로컬스토리지- 사이트에 종속된 반영구 데이터 저장소
    //세션스토리지- 페이지 닫으면 사라지는 데이터 저장소
    //setItem은 값을 문자로 저장해야 한다.
    //localStorage.setItem('user',user) //user객체를 문자화해야 한다.
    localStorage.setItem('user', JSON.stringify(user))
    //console.log(localStorage.getItem('user'))
    console.log('jsObj:', JSON.parse(localStorage.getItem('user')))
    //localStorage.removeItem('user') 
    //localStorage 데이터 수정
    const str = localStorage.getItem('user')
    const obj = JSON.parse(str)
    obj.age = 22
    console.log(obj);
    localStorage.setItem('user', JSON.stringify(obj))
  </script>

 

 

2. 구조 분해 할당

  <script>
    //구조 분해 할당(Destructuring assignment)
    //비구조화 할당
    const user = {
      name: 'kim',
      age: 30,
      email: 'thekim@gmail.com'
    }
    //let name=user.name
    //let age=user.age
    //let email=user.email   불편함..

    //속성이 많을 때 필요한것만 순서상관없이 추출시 유리
    //address속성값이 없다면 'Korea'가 기본값이 된다.
    const {
      age,
      name: irum,
      address = 'Korea'
    } = user
    console.log(age)
    console.log(name)
    //위를 구조분해할당 없이 추출해서 age, name변수에 저장해 볼것
    console.log(`사용자의 이름은 ${irum}입니다`);
    console.log(`${irum}의 나이는 ${age}세입니다`);
    console.log(`${irum}의 이메일은 ${user.mail}입니다`);
    console.log(address);

    showNameAgeInfo(user)

    function showNameAgeInfo({
      name,
      age
    }) {
      console.log(`name=${name},  age=${age}`);
    }

    const fruits = ['Apple', 'Banana', 'Cherry']
    //fruits가 배열이므로 []로 구조분해할것
    //const [a,b,c,d='Mango']=fruits  //순서대로 추출함 
    //console.log(a,b,c,d)  //Apple Banana Cherry undefined
    // const [,b]=fruits  //두번째요소 Banana만 추출함 
    // console.log(b)  //Banana
    const [, , b] = fruits //세번째요소 Cherry만 추출함 
    console.log(b) //Cherry
  </script>

 

 

3. 전개 연산자

  <script>
    //전개 연산자(Spread)
    const fruits = ['Apple', 'Banana', 'Cherry', 'Orange']
    console.log(fruits)
    console.log(...fruits)
    //console.log('Apple','Banana', 'Cherry')와 동일하게 호출
    //c(last매개변수)는 ['Cherry','Orange'] 인자를 받는다                             
    // function toObject(a,b,...c){  
    //   return{
    //     //a: a, b: b, c: c
    //     a, b, c   //키,값변수가 같으면 1번만 명시해도 됨 
    //   }
    // }
    const toObject = (a, b, ...c) => ({
      a,
      b,
      c
    })
    console.log(toObject(...fruits)); //호출 인자가 많을 때 유리함
    //console.log(toObject(fruits[0],fruits[1],fruits[2],fruits[3])); 와 동일하게 호출
  </script>

 

 

4. 불변성

  <script>
    //데이터 불변성(Immutability)
    //원시 데이터 : String, Number, Boolean, undefined, null
    //(값이 같으면 같은 참조값을 갖는다.)
    //(결국, 원시 데이터는 참조값보다는 상수처럼 이해하면 된다.)
    //참조형 데이터: Object, Array, Function
    //(참조형은 불변성이 없다.)
    //(결국, 참조형의 새로운 객체는 새로운 참조값을 갖는다. )
    //----------------------------------------------
    //1번지:      2번지:      3번지:      4번지:
    //----------------------------------------------
    // let a=1
    // let b=4
    // console.log(a,b, a===b)
    // b=a  //참조값이 복사된다.
    // console.log(a,b, a===b)
    // b=7  //7의 참조값이 복사된다. 
    // console.log(a,b, a===b)
    // let c=1
    // console.log(a,b, b===c)
    let a = {
      k: 1
    }
    let b = {
      k: 1
    }
    console.log(a, b, a === b)
    a.k = 7
    b = a //객체값복사가 아니라 참조값이 복사된다.(주의)
    console.log(a, b, a === b)
    a.k = 2 //b객체의 k속성값도 2로 변경되니 주의하자.
    console.log(a, b, a === b)
    let c = b
    console.log(a, b, c, a === c)
    a.k = 9
    console.log(a, b, c, a === c)
  </script>

 

 

5. 얕은 복사와 깊은 복사

  <script>
    //얕은 복사(Shallow copy), 깊은 복사(Deep copy)
    const user = {
      name: "kim",
      age: 40,
      emails: ['thekim@gmail.com']
    }
    //const copyUser =user  //얕은복사
    //const copyUser =Object.assign({}, user)  //깊은복사
    let copyUser = {
      ...user
    } //전개연산자 활용 깊은복사같지만 emails는 얕은복사가 된다.
    let copyUser = {
      name: user.name,
      age: user.age,
      email: user.emails
    }
    console.log(copyUser)
    console.log(copyUser === user) //false 깊은 복사
    console.log(copyUser.email === user.emails) //true 그러나 emails는 얕은복사

    user.age = 22
    console.log('user', user)
    console.log('copyUser', copyUser)
    console.log('-------------');
    console.log('-------------');
    user.emails.push('neo@naver.com')
    console.log(user.emails, copyUser.emails); //얕은복사이므로 같은요소값이 출력됨
    console.log('user', user);
    console.log('copyUser', copyUser);
    //deep copy는 lodash 라이브러리의 cloneDeep()를 이용해서 쉽게 할수 있지만
    //실력을 위해 직접구현해 보자 
    copyUser = {}
    deepCopy(user, copyUser)
    console.log('deepCopy call after')
    console.log(user.emails === copyUser.emails); //깊은복사가 되어 false
    user.emails.push('xxx@naver.com')
    console.log('user', user); //['thekim@gmail.com','neo@naver.com','xxx@naver.com']
    console.log('copyUser', copyUser); //['thekim@gmail.com','neo@naver.com']

    function deepCopy(source, target) {
      target.name = source.name
      target.age = source.age
      target.emails = []
      //문제> source.emails 배열의 값을 순차적으로 target.emails배열로 복사하시오
      for (let email of source.emails) {
        target.emails.push(email)
      }
      //source.emails.forEach(email => target.emails.push(email));
      //target.emails.push(...source.emails)
    }
  </script>

 


  • 37일차는 오후에 조퇴를 하는 바람에 일지가 없다.

 


728x90
728x90

 

수업내용 정리 (VSCode - JS)

 

1. 산술/할당 연산자

    <script>
        // 산술 연산자
        console.log(1+2);
        console.log(parseInt(10/3));
        console.log(10%3);

        let a;
        a+=1;
        console.log(a); //NaN: 숫자가 아님

        a=2;
        a+=1;
        console.log(a);

        
        // 비교연산자
        const b=1;  // final int b=1;
        const c=3;  // final int c=3;
        console.log(b<c);

        function isEqual(x,y){
            return x==y;
        }
        console.log(isEqual(1,1));
        console.log(isEqual(1,2));
        console.log(isEqual(1,'1'));


        // 삼항연산자
        const d=10, e=20, f=30;
    </script>

 

 

2. 삼항 연산자

  <script>
    const a= 1<2
    if(a){
      console.log('참')
    }else{
      console.log('거짓')
    }
    console.log(a?'참':'거짓')
  </script>

 

 

3. 조건문

  <script>
    function random() {
      return Math.floor(Math.random() * 10)
    }
    const a = random()
    if (a === 0) {
      console.log('a is 0')
    }else if(a===2){
      console.log('a is 2')
    }else{
      console.log('rest...')
    }
  </script>
  <script>
    function random() {
      return Math.floor(Math.random() * 10)
    }
    const a = random()
    switch(a){
     case 0:
      console.log('a is 0')
      break;
    case 2:
      console.log('a is 2')
      break;
    default:
      console.log('rest...')
    }
  </script>

 

 

4. 반복문

  <script>
    const ulEl=document.querySelector('ul')
    for(let i=0; i<10; i++){
      const li=document.createElement('li')
      li.textContent=`list-${i+1}`
      if((i+1)%2===0){  //짝수번째 클릭시  
        li.addEventListener('click',function(){
        console.log(li.textContent)
      })
      }
      ulEl.appendChild(li)
    }
        // 나중에 추가적으로 배울 것
  </script>

 

 

5. 변수 유효범위

  <script>
    //var: 함수레벨 scope, 의도하지 않는 범위에서 사용될수 있다.메모리누수
    //let, const: 블록레벨 scope
    function scope(){
      //console.log(a)  // let,const: not defined에러, var: undefined출력
      if(true){
        //console.log(a)  // let,const: not defined에러, var: undefined출력
        var a =123
        //console.log(a)   //모두 정상
      }
      console.log(a)  //let,const: not defined에러, var: 123
    }
    scope()
  </script>

 

 

6. 형변환

  <script>
    //형변환
    const a=1
    const b='1'
    console.log(a===b)  //일치 연산자
    console.log(a==b)  //동등 연산자시 형변환 일어남(비권장)
    //참 값
    //true, {}, [], 1,2,'false',-12, '3.14'.....
    //거짓 값(암기)
    //false, '', null, undefined, 0,-0, NaN(Not a Number)
    if('false'){  //false
      console.log(123)
    }
   console.log('NaN: ', 1+undefined)   //NaN: 숫자에 더할수 없는 값
  </script>

 

 

7. 함수

    <script>
        // 컴파일 언어(java, c, c++...) <---> 인터프리터 언어(js, 파이썬)
        // 기명 함수
        function sum(x,y){
            return x+y;
        }
        let a=sum(1,3);
        const b=sum(1.3, 2.3);
        console.log(a, b);
        console.log(a+b);
        console.log(sum(10,20)+sum(2.3,4.4));

        // 익명함수 (함수를 sum2 변수에 저장)
        // 함수도 객체
        const sum2 = function(x,y){
            if(x<2){
                return;
            }
            return x+y;
        };
        console.log(sum2);
        console.log(sum2(1,3)); // undefined 값이 없을때
        console.log(sum2(4,3));
        // let ulEl=document.getElementById('ul'); // 이것도 객체임

        function sum3(){
            console.log(arguments); //내장된 매개변수
            return arguments[0]+arguments[1]+arguments[2]
        }
        console.log(sum3(3,7,3));

        // 함수 오버로딩없음
        function sum4(x,y,z){
            console.log(x,y,z);
        }
        sum4(); //undefined undefined undefined
        sum4(10);   //undefined undefined
        sum4(10,20);    //undefined
        sum4(10,20,30); //10 20 30
        sum4(10,20,30,40);  //10 20 30
    </script>

 

 

8. 화살표 함수

    <script>
        // const double=function(x){return x*2}
        // console.log('double: ',double(7));
        // const dbArrow=(x)=>{return x*2}
        // const dbArrow= x=> {return x*2}
        // const dbArrow= x=> {x*2}
        // const dbArrow= x=> x*2
        // const dbArrow= x=>{console.log(x); return x*2}
        // console.log('dbArrow: ',dbArrow(8));
        // const dbArrow= ()=> [1,2,3]
        // console.log('arr: ', dbArrow(), dbArrow().length);
        //const dbArrow= (x)=> {name: 'cha', age: x} // 함수의 중괄호인지 객체의 중괄호인지 구분을 못함
        //console.log('obj: ', dbArrow());
        let person={name:'kim', age:20} // 객체
        console.log(person.name, person.age);
    </script>

 

 

9. 즉시 실행함수

    <script>
        const a = 7; // 전역변수
        function double(){
        console.log(a*2);
        }
        double(); // 밑에 즉시실행함수가 있으면 꼭 세미콜론(;)을 붙여줘야한다.

        // 즉시실행함수
        // IIFE, Immediately-Invoked Function Expression
        (function(){
        console.log(a*3);
        })(); // 두 덩어리

        (function(){
        console.log(a*4);
        }()); // 한 덩어리 (권장)
        </script>

 

 

10. 함수 호이스팅

    <script>
        // 호이스팅(Hoisting): 위로 끌어올리다.
        // 함수 선언부가 유효범위 최상단으로 끌어올려지는 현상
        // function double(){}
        const a=7;

        function double(){
            console.log(a*2);
        }
        const square=function(){
            console.log(a*2);
        }
        const square2= ()=> console.log(a*a);
        
        // 익명함수는 호이스팅 불가

        double()
        square()
        square2()
    </script>

 

 

11. 변수 호이스팅

  <script>
    //호이스팅(hoisting)이란
//자바스크립트 함수는 실행되기 전에 함수 안에 필요한 변수값들을 모두 모아서 유효 범위의 최상단에 선언한다.
//자바스크립트 Parser가 함수 실행 전 해당 함수를 한 번 훑는다.
//함수 안에 존재하는 변수/함수선언에 대한 정보를 기억하고 있다가 실행시킨다.
//유효 범위: if,for단위 블록{}내에 변수를 선언해도 유효범위는 function단위 블록 {}이다., 

//호이스팅의 대상
//var 변수 선언과 함수선언문에서만 호이스팅이 일어난다. 함수 표현식은 호이스팅 안됨.
//var 변수/함수의 선언만 위로 끌어 올려지며, 할당은 끌어 올려지지 않는다.

//let/const 변수 선언과 함수표현식에서는 호이스팅이 발생하지 않는다.
//java처럼 if, for단위 블록{}내에 변수를 선언하면 해당{}이 유효범위다. 
		
	//지역변수>전역변수 
const pi = 3.14; //전역 상수변수(global v)

fct1();
fct2(3,5);

function fct1() {
    //var a,b; 함수의 상단에 호이스팅
    //console.log('a: ',a)  //var:undefined, let,const:error
    //console.log('b: ',b)  //var:undefined 
    let a = 100,b = 200; //지역변수(local variable)

    if (1) {
        let a = 30,b = 40; //java error, 위의 const와 let을 var로 변경해 보자.
        console.log("1=" + a);
        console.log("1=" + b);
    }
    console.log(a);  //var는 마지막에 선언된 변수가 위의 변수를 덮어버린다.
    console.log(b);  //let,const는 100, 200
    
    console.log('전역변수:' + pi)
}

function fct2(a, b) { //함수정의부
  console.log('fct2 call:', a, b)  
  console.log('gv:' + pi);
    
}
//메소드 오버로딩은 없지만 유연하다.
fct2()   
fct2(10)
fct2(10,20,30)

//함수선언부는 호이스팅 되지 않음
//    const fct=function(){  //익명 함수
//        console.log("함수 출력");
//    };
//    fct();
//    console.log(typeof fct);

function test(show) {
    show();
}
//ES6 화살표함수=> , 자바 람다(lambda) ->

test(() => {
    console.log('function call');
    console.log('second line');
});
// test(function() {
//      console.log('function call');
//      console.log('second line');
// });
  </script>

 

 

12. 타이머 함수

  <script>
    //타이머 함수: JS 전역함수(어디서든 호출가능한 함수)
    //setTimeout(함수, 시간): 일정 시간 후 함수실행
    //setInterval(함수, 시간): 시간 간격바다 함수 실행
    //clearTimeout(): 설정된 Timeout 함수를 종료
    //clearInterval(): 설정된 Interval 함수를 종료
    // setTimeout(function(){
    //   console.log('hello!')
    // }, 3000)
    // const timer=setTimeout(()=>{
    //   console.log('hello!')
    // }, 3000)
    console.log('비동기 처리')

    const timer = setInterval(() => {
      console.log('hello!')
    }, 3000)

    //h1태그를 클릭하면 
    const h1El = document.querySelector('h1')
    h1El.addEventListener('click', () => {
      //clearTimeout(timer) //setTimeout함수가 작동하지 않음
      clearInterval(timer) //setInterval함수가 작동하지 않음
    })
  </script>

 

 

13. 콜백

<script>
//콜백(Callback)
//함수의 인수로 사용되는 함수
//setTimeout(함수, 시간)
// function timeout(){
//   setTimeout(()=>{
//     console.log('hello!')
//   },3000)
// }
// timeout()
// console.log('Done!') //Done먼저 출력후 3초뒤 hello출력
function timeout(cb){
  //아래 익명함수는 setTimeout의 콜백함수임
  setTimeout(()=>{  
    console.log('hello!')
    cb()   
  },3000)
}
//콜백 함수 사용 목적
//1.익명함수가 timeout의 인자로 사용됨
//2.timeout실행시 특정 위치 실행 보장하기 위해
timeout(()=>{    
  console.log('Done!') 
})
</script>

 

 

14. 생성자 함수

  <script>
    //리터럴({},[],"") 방식의 객체 생성
    // const kim={
    //   //필드
    //   //property
    //   firstName: 'kim',
    //   lastName: 'dong',
    //   //method
    //   getFullName: function(){  //=>함수 금지(this가 상위객체를 의미함)
    //     //this: 현재 소속된 객체데이터를 의미
    //     return `${this.firstName} ${this.lastName}`
    //     //return `${kim.firstName} ${kim.lastName}`
    //   }
    // }
    // console.log(kim.getFullName())
    // const lee={
    //   firstName: 'lee',
    //   lastName: 'na',
    //   getFullName: function(){
    //     return `${this.firstName} ${this.lastName}`    
    //   }
    // }
    // console.log(lee.getFullName())
    //생성자 함수를 이용한 객체 생성
    //java의 클래스와 유사(?)
    //new와 사용하는 생성자함수는 대문자로 지정
    function User(first, last) {
      this.firstName = first //this생략 안됨
      this.lastName = last
      //메모리 비효율적(객체마다 함수객체를 생성함)
      // this.getFullName=function(){  
      //   return `${this.firstName} ${this.lastName}`
      // }
    }
    //메모리 효율적
    //함수객체를 user함수의 prototype에 1번만 생성한다.
    User.prototype.getFullName = function () {
      return `${this.firstName} ${this.lastName}`
    }
    //생성자 함수를 통한 kim인스턴스 생성  
    const kim = new User('kim', 'dong')
    const lee = new User('lee', 'na')
    console.log(kim)
    console.log(lee)
    console.log(kim.getFullName())
    console.log(lee.getFullName());

    //javaScript는 prototype(원형)기반 언어임
    const arr = [1, 2, 3];
    console.log(arr)
    //배열객체의 prototype의 includes메소드 확인
    console.log(arr.includes(4)) //false
    console.log(arr.includes(2)) //true
  </script>

 

 

15. this

  <script>
    //this
    //일반 함수는 (호출 위치!)에서 따라 this정의!
    //화살표 함수는 자신이 (선언된 함수 범위!)에서 this정의!
    const kim={
      name: 'kim',
      normal: function(){
        console.log(this.name)
        console.log(this)  //kim객체
      },
      arrow:()=>{  //특정 함수범위에 선언되고 있지 않음
        console.log(this.name)
        console.log(this)  //window객체
      }
    }
    kim.normal()  //kim 
    kim.arrow()   //'' or undefined
    
    const lee={
      name: 'lee',
      normal:kim.normal,
      arrow: kim.arrow
    }
    //호출위치가 여기! 그래서 this는 lee객체 참조함
    lee.normal();
    //선언된 위치(범위)는 그대로임! this는 window객체 참조함
    lee.arrow();

    // 생성자 함수에서 getFullName을 화살표함수로
    // 만들어서 this값을 확인해보자

    const timer={
      name: 'kim',
      timeout: function(){
        //setTimeout의 내부에서 콜백을 호출중이라서 name출력안됨
        //setTimeout(function(){
        //  console.log('t:', this.name)  //window 객체
        //}, 2000)
        //timer객체의 timeout메소드에 선언되었으므로 name출력됨        
        //setTimeout함수에서는 화살표함수를 쓰는것이 좋다.
        setTimeout(()=>{
          console.log('t:', this.name) //timer객체
        }, 2000)
      }
    }
    timer.timeout()
  </script>

 

 

16. ES6 Classes

  <script>
    const hong = {
      name: 'hong',
      //normal: function(){
      //   console.log(this.name)
      // },
      //위 메소드의 간소화 표현
      normal() {
        console.log(this.name)
      },
	  //화살표함수 간소화 안됨
      arrow: () => {
        console.log(this.name)
      }
    }
    hong.normal()
    hong.arrow()

    ////ES6 Classes
    //생성자 함수활용을 class로 간소화 할 수 있음
    //class는 react에서 많이 활용함
    class User {
      constructor(first, last) {
        this.firstName = first //this생략 안됨
        this.lastName = last
      }
      //prototype에 1번만 생성한다.
      getFullName() {
        return `${this.firstName} ${this.lastName}`
      }
    } //end class
    //생성자 함수를 통한 kim인스턴스 생성  
    const kim = new User('kim', 'dong')
    const lee = new User('lee', 'na')
    console.log(kim)
    console.log(lee)
    console.log(kim.getFullName())
    console.log(lee.getFullName());
  </script>

 

 

17. 상속(확장)

  <script>
    //java class와 아주 유사함
	//생성자 및 메소드객체가 prototype에 1번 생성됨
    class Car{
      constructor(gasoline){
        //super()에러
        this.gasoline=gasoline
      }
      showGuageInfo(){
        console.log('gas: ', this.gasoline)
      }
    }
    class HybridCar extends Car{
      constructor(gasoline, electric){
        super(gasoline)
        this.electric=electric
      }
      showGuageInfo(){
      super.showGuageInfo()
        //console.log('gas: ', this.gasoline)  //가능
        console.log('elec: ', this.electric)
      }
    }
    class HybridWaterCar extends HybridCar{
      constructor(gasoline, electric, water){
        super(gasoline,electric)
        this.water=water
      }
      showGuageInfo(){
        super.showGuageInfo()
        //console.log('gas: ', this.gasoline) //가능
        //console.log('elec: ', this.electric) //가능
        console.log('water: ', this.water)
      }
    }
  const car1=new HybridWaterCar(50,1000,30)
  const car2=new HybridCar(40,500)
  console.log(car1)
  car1.showGuageInfo()
  console.log(car2)
  car2.showGuageInfo()
  </script>

 

 

18. 문자

  <script>
    //JS 데이터
    //String: "", '', ``
    //Number:
    //Boolena: true, false
    //underfinde:
    //null:
    //Array: []
    //Object: {}
    //String.prototype.indexOf() 메소드는 String객체 모두 사용할 수 있다.
    let result='Hello world!'.indexOf('world')
    console.log(result)  //첫글자index는 0부터
    result='Hello world!'.indexOf('kim')
    console.log(result)  //검색실패 -1
    
    const str='대한민국 최고'  //문자열 리터럴 객체 
    //const str=new String('대한민국') //문자열 정식 객체
    console.log(str.length) //7
    console.log(str.indexOf('만세') != -1)  //false
    console.log(str.slice(0,3))  //대한민(idx:0~2)
    console.log(str.slice(5,7))  //최고(idx:5~6)
    console.log(str.slice(2, -1))  //민국 최(idx:2~뒤쪽 1문자미만) 
    console.log(str.replace('대한민국','한국' ))  //한국 최고
    console.log(str.replace(' 최고','' ))  //삭제효과, 대한민국
    const email='surecha@nuri.com'
    console.log(email.match(/.+(?=@)/))  //정규표현식:@앞쪽 문자열 찾아줘 
    console.log(email.match(/.+(?=@)/)[0]) 
    const str2='    Hello world  '
    console.log(str2.trim()) //문자열 앞뒤 공백제거 
  </script>

 

 

19. 숫자와 수학

  <script>
    const pi=3.141592
    console.log(pi)

    const str=pi.toFixed(2)  //'3.14'문자열 반환
    console.log(str)
    console.log(typeof str);
    //window객체 전역함수 parseInt, parseFloat(권장)
    const integer = parseInt(str)
    const float = parseFloat(str)
	//number객체 static 함수: parseInt, parseFloat(비권장)
	//const integer=Number.parseInt(str)
    //const float= Number.parseFloat(str)
    console.log(integer)  //3
    console.log(float)    //3.14 
    console.log(typeof integer, typeof float) //number  number
    //Math: 수학관련 객체
    console.log('abs: ', Math.abs(-12))  //12
    console.log('min: ', Math.min(2,8,5,6))  //2
    console.log('max: ', Math.max(2,8,5,6))  //8
    console.log('ceil: ', Math.ceil(3.14)) //4, 올림함수
    console.log('floor: ', Math.floor(3.14)) //3, 절삭함수
    console.log('round: ', Math.round(3.14)) //3, 반올림함수
    console.log('random: ', Math.random())   //0.0~1.0미만 랜덤함수
    const rand=Math.floor(Math.random() * 10)
    console.log(rand)  //0~9사이 난수 발생
  </script>

 


728x90
1 2 3 4 5 6 7 ··· 27