1.  프로젝트의 구현 목표와 준비

  • 검색과 필터링을 적용할 수 있는 화면을 구성하고 MyBatis의 동적 쿼리를 이용해서 상황에 맞는 Todo들을 검색
  • 새로운 Todo를 등록할 때 문자열, boolean, LocalDate를 자동으로 처리
  • 목록에서 조회 화면으로 이동할 때 모든 검색, 필터링, 페이징 조건을 유지하도록 구성
  • 조회 화면에서는 모든 조건을 유지한 채로 수정 / 삭제 화면으로 이동하도록 구성
  • 삭제 시에는 다시 목록 화면으로 이동
  • 수정 시에는 다시 조회 화면으로 이동하지만, 검색, 필터링, 페이징 조건은 초기화

(1) 프로젝트의 준비

build.gradle 설정 코드
    // 1. 스프링 관련
    // https://mvnrepository.com/artifact/org.springframework/spring-core
    implementation 'org.springframework:spring-core:5.3.30'
    implementation 'org.springframework:spring-context:5.3.30'
    implementation 'org.springframework:spring-test:5.3.30'
    implementation 'org.springframework:spring-webmvc:5.3.30'

    implementation 'org.springframework:spring-jdbc:5.3.30'
    implementation 'org.springframework:spring-tx:5.3.30'

 
    // 2. JSTL   
    // https://mvnrepository.com/artifact/javax.servlet/jstl
    implementation 'javax.servlet:jstl:1.2'


    // 3. MyBatis / MySQL / HikariCP 관련
    // https://mvnrepository.com/artifact/mysql/mysql-connector-java
    implementation 'mysql:mysql-connector-java:8.0.33'
    // https://mvnrepository.com/artifact/com.zaxxer/HikariCP
    implementation 'com.zaxxer:HikariCP:5.0.1'
    // https://mvnrepository.com/artifact/org.mybatis/mybatis
    implementation 'org.mybatis:mybatis:3.5.9'
    // https://mvnrepository.com/artifact/org.mybatis/mybatis-spring
    implementation 'org.mybatis:mybatis-spring:2.0.7'


    // 4. DTO와 VO의 변환을 위한 ModelMapper
    // https://mvnrepository.com/artifact/org.modelmapper/modelmapper
    implementation 'org.modelmapper:modelmapper:3.0.0'


    // 5. DTO 검증을 위한 validate 관련 라이브러리
    // https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator
    implementation 'org.hibernate.validator:hibernate-validator:6.2.1.Final'

 


 

(2) 프로젝트의 폴더 / 패키지 구조

테이블 생성
CREATE TABLE `tbl_todo` (
    `tno` int auto_increment PRIMARY KEY,
    `title` varchar(100) not null,
    `dueDate` date not null,
    `writer` varchar(50) not null,
    `finished` tinyint default 0
)

 

패키지 구조

 


 

(3) ModelMapper 설정과 @Configuration

👩🏻‍💻  프로젝트 개발에는 DTO를 VO로 변환하거나 VO를 DTO로 변환해야 하는 작업이 빈번하므로 이를 처리하기 위해서 ModelMapper를 스프링의 빈으로 등록해서 처리

  • config패키지에  ModelMapperConfig 클래스 생성
  • ModelMapperConfig는 @Configuration을 이용
  • @Configuration은 해당 클래스가 스프링 빈에 대한 설정을 하는 클래스임을 명시
@Configuration
public class ModelMapperConfig {
    @Bean
    public ModelMapper getMapper() {
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.getConfiguration()
                .setFieldMatchingEnabled(true)
                .setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE)
                .setMatchingStrategy(MatchingStrategies.STRICT);
        return modelMapper;
    }
}

 

  ✓  ModelMapperConfig 클래스 내에는 getMapper()라는 메서드가 ModelMapper를 반환하도록 설계
  ✓  getMapper() 선언부에 있는 @Bean 어노테이션은 해당 메서드의 실행 결과로 반환된 객체를 스프링의 빈으로 등록시키는 역할

 

  • ModelMapperConfig를 스프링 빈으로 인식할 수 있도록 root-context.xml에 config 패키지를 component-scan을 이용해서 추가
<context:component-scan base-package="com.example.spring_ex_01_2404.config"/>

 


2.  화면 디자인 - 부트 스트랩 적용

👩🏻‍💻   JSP 파일을 작성하기 전, 프로젝트의 시작 단계에서 화면 디자인을 결정하는 것이 좋음
         ✓
화면 디자인 없이 개발을 진행할 때는 나중에 코드를 다시 입혀야 하는 작업을 할 수도 있기 때문
👩🏻‍💻 
최근에는 부트스트랩 (bootstrap)이나 머터리얼(Material Design)과 같이 쉽게 웹 화면을 디자인할 수 있는 라이브러리들 덕분에 전문적인 웹 디자이너의 도움 없이도 어느정도 완성도가 있는 디자인 작업이 가능해 짐

 

https://elements.envato.com/web-templates/site-templates

 

HTML Website Templates - Envato Elements

Browse our Collection of fully customizable HTML templates. Get Unlimited Downloads with a subscription with Envato Elements.

elements.envato.com

 

📌  webapp의 resources 폴더에 test.html을 작성해서 부트스트랩을 적용하는 페이지를 작성

 

✓  부트스트랩의 화면 구성에는 container와 row를 이용


✓  Card 컴포넌트 적용하기

    부트스트랩에는 화면을 쉽게 제작할 수 있는 여러 종류의 컴포넌트를 제공
    이중에서 Card라는 컴포넌트를 적용해서 현재의 화면에서 Content라는 영역을 변경


✓  Navbar 컴포넌트의 적용
    화면 상단에는 간단한 메뉴를 보여줄 수 있는 Nav 혹은 Navbar 컴포넌트를 적용
    공식 문서의 Navbar의 예제를 선택해서 Header 라고 출력되는 부분에 적용


✓  Footer 처리
    맨 아래 <div class="row">에는 간단한 <footer>를 적용
    해당 <div>를 맨 아래쪽으로 고정하기 위해서 fixed-bottom을 적용
    내용이 많은 경우에는 Footer 영역으로 인해 가려질 수 있는 부분이 있으므로 z-index 값은 음수로 처리해서 가려질 수 있도록 구성

 

<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">

    <title>Hello, world!</title>
</head>

<body>
<div class="container-fluid">
    <div class="row">
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <div class="container-fluid">
                <a class="navbar-brand" href="#">Navbar</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
                    <div class="navbar-nav">
                        <a class="nav-link active" aria-current="page" href="#">Home</a>
                        <a class="nav-link" href="#">Features</a>
                        <a class="nav-link" href="#">Pricing</a>
                        <a class="nav-link disabled">Disabled</a>
                    </div>
                </div>
            </div>
        </nav>
        
        <div class="row content">
            <div class="col">
                <div class="card">
                    <div class="card-header">
                        Featured
                    </div>
                    <div class="card-body">
                        <h5 class="card-title">Special title treatment</h5>
                        <p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
                        <a href="#" class="btn btn-primary">Go somewhere</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <div class="row content">
        <h1>Content</h1>
    </div>
    <div class="row footer">
        <div class="row fixed-bottom" style="z-index: -100">
            <footer class="py-1 my-1">
                <p class="tab-content text-muted">Footer</p>
            </footer>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
        crossorigin="anonymous"></script>

</body>
</html>

 

 

 

[ 내용 참고 : IT 학원 강의 ]


1.  버스 노선 가져오기

html 코드
<body>
<table>
    <thead>
        <tr>
            <th>버스번호</th>
            <th>버스등급</th>
            <th>평일요금</th>
            <th>평일 시간표</th>
            <th>주말 시간표</th>
        </tr>
    </thead>
    <tbody>

    </tbody>
</table>
<div>
    <input type="button" value="대구">
    <input type="button" value="구미">
    <input type="button" value="경산">
    <input type="button" value="포항">
</div>
</body>

 

css 코드
table, td, th {
    border-collapse: collapse;
    border: 2px solid black;
}

table th {
    height: 50px;
}

table td {
    padding: 15px;
}


table th:first-child {
    width: 200px;
}

table th:nth-child(2) {
    width: 100px;
}

table th:nth-child(3) {
    width: 200px;
}

table th:nth-child(4) {
    width: 550px;
}

table th:last-child {
    width: 550px;
}

div {
    margin: 0 auto;
    padding: 20px;
    text-align: center;
    width: 1000px;
}
div input {
    width: 70px;
    height: 40px;
    background-color: #3a4bb9;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    padding: 5px 10px;
}
div input:hover {
    background-color: white;
    color: #3a4bb9;
}

자바스크립트 코드
document.addEventListener('DOMContentLoaded', function () {

    const btns = document.querySelectorAll('[type=button]');

    btns.forEach(function (item) {
        item.addEventListener('click', function () {
            const cityName = item.getAttribute('value'); // value 값 변수에 담기
            let url = getUrl() // 함수값을 변수에 담기
            printlist(url, cityName); // 함수 호출
        });
    });

    // 1, 2 터미널 각각 분류된 평일 및 주말 시간표를 합치는 함수 만들기
    const sortStr = function (string1, string2) { 
        // 기본 데이터는 문자열. 2개의 문자열을 결합하고, ',' 기준으로 배열로 변환
        let tempList = (string1 + ', ' + string2).split(",");
        tempList = [...new Set(tempList)]; // set으로 중복값 제거
        tempList = tempList.map((item) => item.trim()) // 공백제거
        tempList.sort(); // 오름차순 정렬

        // 현재 시간 구해서 지나간 시간이면 연하게 출력.
        const today = new Date();
        const todayTime = `${today.getHours()}${today.getMinutes()}`;
        // console.log(todayTime)
        tempList = tempList.map((item) => {
            console.log(Number(item))
            return Number(item) < Number(todayTime) ? `<span style="color: #cccccc">${item}</span>` : item;
        });

        return tempList.join(", "); // 배열을 문자열로 변환
    }

    const getUrl = function () {
        const service_key = 'uAhO32pV0qa7BDOmkJLhw2ZyOB9i5bGj7cMN8cuuHmKIwyyf29lHLjym8hBXdIaXyvAI1IyLvQZopk5HW233qQ=='
        const para = `?serviceKey=${service_key}&area=6&numOfRows=100&pageNo=1&type=json`
        return 'http://apis.data.go.kr/B551177/BusInformation/getBusInfo' + para
        // console.log(url)
    }

    const printlist = function (getUrl, cityName) {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', getUrl);
        xhr.onreadystatechange = () => {
            
            if (xhr.readyState !== XMLHttpRequest.DONE) return;

            if (xhr.status === 200) {
                console.log(xhr.response);
                jsonData = JSON.parse(xhr.response);
                //console.log(jsonData);

                const routes = jsonData.response.body.items;
                //console.log(routes)
                const tBody = document.querySelector("tbody");

                while (tBody.firstChild) {
                    tBody.removeChild(tBody.firstChild);
                }

                for (route of routes) {
                    //console.log(route["routeinfo"])

                    if (route["routeinfo"].indexOf(cityName) !== -1) {
                        const trTag = document.createElement('tr');
                        console.log(route)

                        trTag.innerHTML = `
                            <td>${route["busnumber"]}</td>
                            <td>${route["busclass"]}</td>
                            <td>${route["adultfare"]}</td>
                            <td>${sortStr(route["t1wdayt"], route["t2wdayt"])}</td>
                            <td>${sortStr(route["t1wt"], route["t2wt"])}</td>`

                        tBody.appendChild(trTag);
                    }
                }

            } else {
                console.error('Error', xhr.status, xhr.statusText);
            }
        }
        xhr.send();
    }
});

 


2.  항공 출도착 정보 

html 코드
<body>
<table>
    <div>
        <input type="button" id="NRT" value="나리타">
        <input type="button" id="CTS" value="삿포로">
        <input type="button" id="KIX" value="오사카/간사이">
        <input type="button" id="FUK" value="후쿠오카">
        <input type="button" id="HKG" value="홍콩">
    </div>

    <thead>
    <tr>
        <th>항공사</th>
        <th>편명</th>
        <th>예정시간</th>
        <th>도착지 공항</th>
    </tr>
    </thead>
    <tbody>

    </tbody>
</table>
</body>

 

css 코드
table {
    margin: 20px auto;
}

table, td, th {
    border-collapse: collapse;
    border: 2px solid black;
}

table th {
    height: 50px;
}

table td {
    padding: 15px;
    text-align: center;
}


table th:first-child {
    width: 200px;
}
table th:nth-child(2) {
    width: 60px;
}
table th:nth-child(3) {
    width: 150px;
}
table th:nth-child(4) {
    width: 160px;
}

div {
    margin: 0 auto;
    padding: 20px;
    text-align: center;
    width: 1000px;
}
div input {
    width: 100px;
    height: 40px;
    background-color: #3a4bb9;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    padding: 5px 10px;
}
div input:hover {
    background-color: white;
    color: #3a4bb9;
}

자바스크립트 코드
document.addEventListener('DOMContentLoaded', function () {
    const btns = document.querySelectorAll('[type=button]');

    btns.forEach(function (item) {
        item.addEventListener('click', function () {
            const airport = item.getAttribute("id");
            let url = getUrl(airport)
            printList(url);
        });
    });

    const getUrl = function (airportCode) {
        const service_key = 'uAhO32pV0qa7BDOmkJLhw2ZyOB9i5bGj7cMN8cuuHmKIwyyf29lHLjym8hBXdIaXyvAI1IyLvQZopk5HW233qQ=='
        const para = `?type=json&ServiceKey=${service_key}&airport_code=${airportCode}`
        return 'http://apis.data.go.kr/B551177/StatusOfPassengerFlightsDSOdp/getPassengerDeparturesDSOdp' + para
    }
    //console.log(getUrl())

    const printList = function (getUrl) {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', getUrl);
        xhr.onreadystatechange = () => {
            // readyState 프로퍼티의 값이 DONE : 요청한 데이터의 처리가 완료되어 응답할 준비가 완료됨.
            if (xhr.readyState !== XMLHttpRequest.DONE) return;

            if (xhr.status === 200) { // 서버(url)에 문서가 존재함
                //console.log(xhr.response);
                const jsonData = JSON.parse(xhr.response);
                //console.log(jsonData);

                const airlines = jsonData.response.body.items;
                //console.log(airlines)

                const tBody = document.querySelector("tbody");

                while (tBody.firstChild) {
                    tBody.removeChild(tBody.firstChild);
                }

                for (airline of airlines) {

                    const list = document.createElement('tr');

                    list.innerHTML = `
                    <td>${airline['airline']}</td>
                    <td>${airline['flightId']}</td>
                    <td>${airline['estimatedDateTime']}</td>
                    <td>${airline['airport']}</td>`

                    tBody.appendChild(list);
                }

            } else {
                console.error('Error', xhr.status, xhr.statusText);
            }
        }
        xhr.send();
    }
});

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


 

1.  localStorage 객체

 

👾  웹 브라우저에 데이터를 저장하는 객체

👾  localStorage 객체 처럼 웹 브라우저가 제공해주는 기능을 웹 API 라고 부른다.

메소드 설명
localStorage.getItem(키) 저장된 값을 추출. 없으면 'null' 이 반환
localStorage.setItem(키, 값) 값을 저장
localStorage.removeItem(키) 특정 키의 값을 제거
localSorage.clear() 저장된 모든 값을 제거

 

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style>
    .hidden {
        display: none;
    }
</style>

<body>
<form id="login-form"> <!-- input 유효성 검사 작동 위해 form 안에 들어가 있어야 함 -->
    <input
            required
            maxlength="15"
            type="text"
            placeholder="What is your name?" />
    <input type="submit" value="Log In">
</form>
<h1 id="greeting" class="hidden"></h1>
<script src="app.js"></script>

</body>
</html>
const loginForm = document.querySelector('#login-form');
const loginInput = document.querySelector('#login-form input');
const greeting = document.querySelector("#greeting");

const HIDDEN_CLASSNAME = "hidden";
const USERNAME_KYE = 'userName';
function onLoginSubmit(event) { // 방금 일어난 event에 대한 정보를 지닌 argument를 채워넣음
    // form을 submit 하면 브라우저는 기본적으로 페이지를 새로고침 함
    event.preventDefault(); // 브라우저 기본 동작 막음 (새로고침 x)
    const userName = loginInput.value; // 입력받은 값 변수에 저장
    loginForm.classList.add(HIDDEN_CLASSNAME); // 입력받은 후 폼 형태 숨기기
    localStorage.setItem(USERNAME_KYE, userName); // (키,값) 형태로 저장
    paintGreetings(userName); // h1 태그 안의 텍스트 불러옴
}

function paintGreetings (userName) { // h1 태그 안의 텍스트 불러오는 함수
    greeting.innerText = `Hello ${userName}`;
    greeting.classList.remove(HIDDEN_CLASSNAME); // 인사말 숨기는 속성 제거
}

const savedUsername = localStorage.getItem(USERNAME_KYE);

if (savedUsername === null) { // 이름이 저장되어 있지 않을 떄
    loginForm.classList.remove(HIDDEN_CLASSNAME); // 로그인 폼 숨기는 속성 제거
    loginForm.addEventListener('submit', onLoginSubmit);
} else { // 이름이 저장되어 있을 떄
    paintGreetings(savedUsername);
}

 

 

웹 API 관련 참고 사이트

https://developer.mozilla.org/ko/docs/Web/API 

 

Web API | MDN

웹 코드를 작성한다면 많은 API를 사용할 수 있습니다. 아래 목록은 웹 앱이나 웹 사이트를 만들 때 사용할 수 있는 모든 인터페이스(객체의 유형)입니다.

developer.mozilla.org

 

 

 

[ 내용 참고 : 책 '혼자 공부하는 자바스크립트' 및 노마드 코더 강의 ]


1.  주문서

 

body 태그
<body>
<!-- 배송 정보 자동으로 입력하기 1 -->
<div id="container">
    <form name="order">
        <fieldset>
            <legend> 주문 정보</legend>
            <ul>
                <li>
                    <label class="field" for="billingName">이름 : </label>
                    <input type="text" class="input-box" id="billingName" name="billingName">
                </li>
                <li>
                    <label class="field" for="billingTel">연락처 : </label>
                    <input type="text" class="input-box" id="billingTel" name="billingTel">
                </li>
                <li>
                    <label class="field" for="billingAddr">주소 : </label>
                    <input type="text" class="input-box" id="billingAddr" name="billingAddr">
                </li>
            </ul>
        </fieldset>
    </form>
    <form name="shipping">
        <fieldset>
            <legend> 배송 정보</legend>
            <ul>
                <li>
                    <input type="checkbox" id="shippingInfo" name="shippingInfo">
                    <label class="check">주문 정보와 배송 정보가 같습니다</label>
                </li>
                <li>
                    <label class="field" for="shippingName">이름 : </label>
                    <input type="text" class="input-box" id="shippingName" name="shippingName">
                </li>
                <li>
                    <label class="field" for="shippingTel">연락처 : </label>
                    <input type="text" class="input-box" id="shippingTel" name="shippingTel">
                </li>
                <li>
                    <label class="field" for="shippingAddr">주소 : </label>
                    <input type="text" class="input-box" id="shippingAddr" name="shippingAddr">
                </li>
            </ul>
        </fieldset>
    </form>
    <button type="submit" class="order">결제하기</button>

</div>
</body>

 

order.css
* {
    margin:0;
    padding:0;
    box-sizing: border-box;
}
ul {
    list-style: none;
}
legend {
    font-size:1.2em;
    font-weight:bold;
    margin-left:20px;
}

form {
    width:520px;
    height:auto;
    padding-left:10px;
    margin:50px auto;
}
fieldset {
    border:1px solid #c0c0c0;
    padding:30px 20px 30px 30px;
    margin-bottom:35px;
}

.field {
    float:left;
    width:60px;
    font-weight:bold;
    font-size:0.9em;
    line-height: 55px;
    text-align:right;
    margin-right:15px;
}

.input-box {
    width:350px;
    height:35px;
    border:1px solid #aaa;
    border-radius:5px;
    padding:5px;
    margin:10px 0;
    float:left;
}

.order {
    width:100%;
    padding:20px;
    border:1px solid #aaa;
    background:#e9e9e9;
    font-size:1em;
    font-weight:bold;
}

 

stylesheet와 body 요소만 적용했을 때


'주문 정보와 배송 정보가 같습니다' 클릭 시 주문 정보 가지고 오고, 클릭 해제시 정보 지우는 코드
<head>
    <link rel="stylesheet" href="css/order.css">
    <script>
  
        document.addEventListener('DOMContentLoaded', function () {
            const check = document.querySelector('#shippingInfo'); 
            // 체크박스의 id는 shippingInfo

            check.addEventListener('click', function () { 
            // check 요소에 click 이벤트가 발생했을 때 실행할 함수
            
                if (this.checked) { // 체크 되었을 때
                    document.querySelector('#shippingName').value = document.getElementById('billingName').value;
                    document.querySelector('#shippingTel').value = document.getElementById('billingTel').value;
                    document.querySelector('#shippingAddr').value = document.getElementById('billingAddr').value;
                } else { // 체크 해제되었을 때 배송정보 지움
                    document.querySelector('#shippingName').value = "";
                    document.querySelector('#shippingTel').value = "";
                    document.querySelector('#shippingAddr').value = "";
                }

            });
        });
    </script>
</head>

 


💡  폼 요소 접근 방법 3가지 

    1. id 값이나 class 값을 사용해 폼 요소에 접근하기
        👾  id 값이나 class 값을 사용해 폼 요소에 접근하는 방법은 DOM의 다른 요소에 접근하는 것과 같음
        👾  querySelector() 함수나 querySelectorAll() 함수를 사용
        👾  텍스트 필드에 있는 값을 가져오기 위해서는 텍스트 필드에 접근하는 소스 뒤에 value 속성을 붙임
console.log(document.getElementById('billingName').value)
console.log(document.querySelector('[name=billingName]').value);

    2. name 값을 사용해 폼 요소에 접근하기
       👾  폼 요소에 id나 class 속성이 없고 name 속성만 있는 경우 name 식별자를 사용해 폼 요소에 접근
       👾  이 방법을 사용하려면 <form> 태그에 name 속성이 지정되어 있어야 하고,
             <form> 태그안에 포함된 폼 요소에도 name 속성이 있어야
       👾  폼 안에 있는 텍스트 필드에 접근하려면 <form>의 name 값과 텍스트 필드의 name 값을 사용
       👾  submit시에 input의 name은 서버로 전송. 하지만 form의 name은 서버로 전송되지 않음
console.log(document.order.billingName.value);

    3. 폼 배열을 사용해 폼 요소에 접근하기
        👾  document의 속성 중 forms 속성은 문서 안에 있는 <form> 태그를 모두 가져와 배열 형태로 반환
        👾  이 방법은 폼 요소에 id나 class 속성도 없고 name 속성도 없을 때 유용
        👾  <form> 태그 안에 포함된 요소에 접근하려면 elements 속성을 사용
                 ➡️  해당 폼 안에 있는 모든 폼 요소를 가져오는 속성, 인덱스 번호로 접근
console.log(document.forms[0].elements[1].value);

 

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


1.  제어문

👩🏻‍💻  제어문 : 코드의 흐름을 조건에 따라 바꿀 수 있음
👩🏻‍💻  제어문에는 크게 조건문에 해당하는 if, when 그리고 반복문에 해당하는 for, while 이 있음


(1)  조건문  if


    ✏️   주어진 조건식의 결과값이 참인지 거짓인지에 따라 코드르 실행할 것인지
           혹은 다른 코드를 실행할 것인지 판단하기 위한 프로그래밍 문법

  1) if문을 사용하기 위한 조건


      -  if문의 조건식에는 비교 연산자(==, <, >)와 논리 연산자(&&, ||)를 사용한 조건식만 사용 가능
      -  조건식의 결과는 Boolean 타입인 true 참과 false 거짓


  2) 기본적인 if문 사용하기

if (조건식) {
        조건식이 참일 경우 실행되는 코드 영역
 } 
    *  코드 블럭 code block. 코드 스코프 code scope : 코드 중간의 여는 중괄호 {로 시작해 닫는 괄호 } 까지
fun main() {
  
    var out = 0
    var strike = 3
    if (strike > 2) {
        out = out + 1
    }
    println("out: $out") // out: 1
    
}


  3) if~else 문 사용하기

if (조건식) {
        조건식이 참일 경우 실행되는 코드 영역
} else {
        조건식이 거짓일 경우 실행되는 코드 영역
}    
fun main() {
    var ball = 4
    if (ball > 3) {
        println("4볼로 출루합니다.") // 4볼로 출루합니다.
    } else {
        println("타석에서 다음 타구를 기다립니다.")
    }
}

 



    4) else if 문

 if (조건식) {
        조건식이 참일 경우 실행되는 코드 영역
 } else if (조건식 2) {
        조건식 1 결과가 거짓이고 조건식 2 결과가 참일 경우 실행되는 코드 영역
} else {
        조건식1, 조건식2 모두 거짓일 경우 실행되는 코드 영역
}


  5) 변수에 직접 if문 사용하기


      -  if문의 조건식 결과를 변수에 대입할 수 있음

fun main () { 
    var a = 5
    var b = 3
    var bigger = if (a > b) a else b
    println("bigger: $bigger")  // 5
}


  6) if문의 마지막 값을 반환값으로 사용하기


    -  위의 코드와 같은데 if문의 코드 영역이 여러 줄일 경우에도 마지막 줄을 변수값으로 사용할 수 있음

fun main() {

    bigger = if (a>b) {
        var c = 30
        a // 마지막 줄의 a 값이 bigger에 저장
    } else {
        b
    }
    println("bigger: $bigger") // 5

    /*
    다음과 같이 'if문을 활용하여 변수에 값을 할당할 수 있음.'
    '값을 할당해야 하므로 반드시 else문이 필요'
     */
    val myAge = 20
    val isAdult = if (myAge > 20) true else false

    println("성인 여부 : $isAdult") // 성인 여부 : false
}

응용 예제
fun main() {
    /*
    사용자에게 성적을 입력받아
    if문을 사용해서 학점을 출력하는 코드를 완성하세요.
    입력은 0 ~ 100까지 입력이 됩니다.
    * 기준
    A: 90 ~ 100
    B: 80 ~ 89
    C: 70 ~ 79
    D: 60 ~ 69
    F: 0 ~ 59

    예) 성적을 입력하세요 : 81
       학점 B
     */

    print("성적을 입력하세요 : ")
    val scanner = Scanner(System.`in`)
    val score = readln().toInt()

    if (score >= 90) print("학점 A")
    else if (score >= 80) print("학점 B")
    else if (score >= 70) print("학점 C")
    else if (score >= 60) print("학점 D")
    else print("학점 F")
}

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


1.  키보드 이벤트

이벤트 설명
keydown 키가 눌릴 때 실행. 키보드를 꾹 누르고 있을 때도, 입력될 때도 실행
keypress 키가 입력되었을 때 실행. 공백이 들어가기 전까지 글자수를 세지 x
웹 브라우저에 따라서 아시아권의 문자를 제대로 처리 못하는 문제가 있음
keyup 키보드에서 키가 떨어질 때 실행

 

<head>
    <script>
        // 남은 글자수 출력하기
        document.addEventListener('DOMContentLoaded', () => {
            const textarea = document.querySelector('textarea');
            const h1 = document.querySelector('h1');

            textarea.addEventListener('keyup', () => { // 키보드에서 키가 떨어질 때 실행
                // value 속성으로 입력양식(form 태그)의 글자(문자열)을 읽을 수 있음.
                const length = textarea.value.length
                h1.textContent = `글자 수: ${length}`;
            })

            textarea.focus();
        });
    </script>
</head>
<body>
    <h1>글자 수: 0</h1>
    <textarea></textarea>
</body>


2.  키보드 키 코드 사용하기

키보드 이벤트 관련 속성
이벤트 속성 이름 설명
code 입력한 키
keyCode 입력한 키를 나타내는 숫자
altKey Alt 키를 눌렀는지
ctrlKey Ctrl 키를 눌렀는지
shiftKey Shift 키를 눌렀는지 


   👩🏻‍💻  code 속성은 입력한 키를 나타내는 문자열이 들어있고
         altKey, ctrlKey, shiftKey 속성은 해당 키를 눌렀는지 불 자료형이 들어 있음

<head>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const h1 = document.querySelector('h1');
            const print = (event) => {
                let output = '';
                output += `alt: ${event.altKey}<br>`; 
                // 이벤트가 발생하면 불 값을 반환
                output += `ctrl: ${event.ctrlKey}<br>`;
                output += `shift: ${event.shiftKey}<br>`;
                // event.code가 있으면 event.code를 출력하고, 
                // undefined라면 event.keyCode를 출력
                output += `code: ${typeof(event.code) !== 'undefined' ? 
                                   event.code : event.keyCode}<br>`;
                h1.innerHTML = output;
            }

            document.addEventListener('keydown', print); // 키가 눌릴 때 출력
            document.addEventListener('keyup', print); // 키가 떨어질 때 출력
        });
    </script>
</head>
<body>
    <h1></h1>
</body>

 


keyCode 속성 활용 

 

    keyCode 속성은 입력한 키를 숫자로 나타냄. 37, 38, 39, 40이 방향키 왼쪽, 위, 오른쪽, 아래를 나타냄

<head>
    <script>       
        document.addEventListener('DOMContentLoaded', () => {
            // 별의 초기 설정
            const star = document.querySelector('h1');
            star.style.position = 'absolute'; // style 속성을 조작하여 position 값을 설정
            star.style.transitionDuration = '1s';

            // 별의 이동을 출력하는 기능
            let [x, y] = [5, 5];
            const block = 20;
            const print = () => {
                star.style.left = `${x * block}px`;
                star.style.top = `${y * block}px`;
            }
            print();

            // 별을 이동하는 기능
            const [left, up, right, down] = [37, 38, 39, 40]; // 방향키 keyCode를 쉽게 사용하기 위해 변수를 사용해 이름을 붙임.
            document.body.addEventListener('keydown', (event) => { // 키보드 눌릴 때 실행

                switch (event.keyCode) {
                    case left:
                        x -= 1;
                        break;
                    case up:
                        y -= 1;
                        break;
                    case right:
                        x += 1;
                        break;
                    case down:
                        y += 1;
                        break;
                }
                print();
            })

            const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];
            const size = [10, 20, 30, 40, 50];
            let index = 0;
            setInterval(() => {
                star.style.color= colors[index++ % colors.length];
                star.style.fontSize = String(size[index++ % size.length]) + 'px'
            }, 500)

        });
    </script>
</head>
<body>
    <h1>★</h1>
</body>

 


3.  이벤트 발생 객체

(1) 이벤트 리스너를 외부로 빼낸 경우

<script>
const listener = (event) => {
    const length = textarea.value.length
    h1.textContent = `글자 수: ${length}`
}

document.addEventListener('DOMContentLoaded', () => { // 외부로 분리
    const textarea = document.querySelector('textarea')
    const h1 = document.querySelector('h1')
    textarea.addEventListener('keyup', listener)
})    
</script>

 

  👩🏻‍💻  코드의 규모가 커지면 위와 같이 이벤트 리스너를 외부로 분리하는 경우가 많아짐

 

이벤트를 발생시킨 객체에 접근하는 방법

 

    📌  event.currentTarget 속성을 사용

         - () => {} 와 function () {} 형태 모두 사용 가능

    📌  this 키워드를 사용

         - 화살표 함수가 아닌 function () {} 형태로 함수를 선언한 경우에 사용

 

currentTarget 속성 사용
<script>
const listener = (event) => {
    const length = event.currentTarget.value.length
    // event.currentTarget이 textarea
    h1.textContent = `글자 수: ${length}`
}

document.addEventListener('DOMContentLoaded', () => { // 외부로 분리
    const textarea = document.querySelector('textarea')
    const h1 = document.querySelector('h1')
    textarea.addEventListener('keyup', listener)
})    
</script>

 

this 키워드 사용
<script>
const listener = function (event) {
    const length = this.value.length
    // this가 textarea
    h1.textContent = `글자 수: ${length}`
}

document.addEventListener('DOMContentLoaded', () => { // 외부로 분리
    const textarea = document.querySelector('textarea')
    const h1 = document.querySelector('h1')
    textarea.addEventListener('keyup', listener)
})    
</script>

 


 

(2) 글자 입력 양식 이벤트

 

  👩🏻‍💻  입력 양식 form : 사용자로부터 어떠한 입력을 받을 때 사용하는 요소

            ex. input, textarea, button, select

 

입력 양식을 기반으로 inch를 cm 단위로 변환하는 프로그램
<head>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const input = document.querySelector('input');
            const btn = document.querySelector('button');
            const p = document.querySelector('p');

            btn.addEventListener('click', () => {
               const inch = Number(input.value); // 입력한 값을 숫자로 변환.

                if (isNaN(inch)) { // 숫자가 아니라면 바로 리턴. isNaN()함수 : 숫자인지 확인. not a number
                    p.textContent = '숫자를 입력해주세요.';
                    return;
                }
               // 변환해서 출력
               const cm = inch * 2.54;
               p.textContent = `${cm}cm`;
            });
        });
    </script>
</head>
<body>
    <input type="text">inch<br>
    <button>계산</button>
    <p></p>
</body>

 


 

이메일 형식 확인하기
<head>
    <script>

        document.addEventListener('DOMContentLoaded', () => {
           const input = document.querySelector('input');
           const p = document.querySelector('p');

           const isEmail = (value) => { // 이메일인지 검사하는 함수
               // 골뱅이를 갖고 있고 && 골뱅이 뒤에 점이 있다면
               return (value.indexOf('@' > 1) && (value.split('@')[1].indexOf('.') > 1));
           };

           input.addEventListener('keyup', function (event) {
               const value = event.currentTarget.value;
               // const value = input.value; 가능
               // console.log(value);

               if (isEmail(value)) {
                   p.style.color = 'green';
                   p.textContent = `이메일 형식입니다: ${value}`;
               }
               else {
                   p.style.color = 'red';
                   p.textContent = `이메일 형식이 아닙니다: ${value}`;
               }
           });
        });
    </script>
</head>
<body>
    <input type="text">
    <p></p>
</body>

 

 

[ 내용참고 : IT 학원 강의 및 책 '혼자 공부하는 자바스크립트' ]

+ Recent posts