<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>minni_.log</title>
        <link>https://velog.io/</link>
        <description>풀스택 개발자</description>
        <lastBuildDate>Fri, 05 Jul 2024 15:10:56 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>minni_.log</title>
            <url>https://velog.velcdn.com/images/minni_/profile/0a9a9bee-8454-4baf-b817-22f768285a76/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. minni_.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/minni_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[정보처리기사 개념 정리 및 오답노트]]></title>
            <link>https://velog.io/@minni_/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@minni_/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 05 Jul 2024 15:10:56 GMT</pubDate>
            <description><![CDATA[<p>[이해안가는 개념  및 한번더 보면 좋을 개념 모음집 - 1과목]</p>
<p>*요구 사항 명세기법 
[정형 명세법]</p>
<ul>
<li>수학적 기반/ 모델링 기반</li>
<li>Z, VDM, Petri-Net(모형기반)</li>
<li>CSP, CCS, LOTOS(대수적방법)</li>
<li>시스템 요구특성이 정확하고 명세가 간결하다. 명세와 구현이 일치.</li>
<li>그러나 이해도가 낮으며 이해관계자의 작성 부담 가중.</li>
</ul>
<ol>
<li>수학적 기호, 정형화된 표기법으로 작성</li>
<li>정확하고 간결하게 표현할 수 있지만 표기법이 어려워 사용자가 이해하기 어렵다.</li>
<li>일관성이 있다.</li>
</ol>
<p>[비정형 명세법]</p>
<ul>
<li>상태, 기능, 객체 중심 명세법</li>
<li>FSM(Finite state machine)</li>
<li>Decision Table, ER모델링</li>
<li>State chart(SADT)</li>
<li>UseCase : 사용자기반모델링</li>
<li>명세 작성이 간편하고 의사전달 방법이 다양하다. </li>
<li>불충분한 명세가능성, 모호성.</li>
</ul>
<ol>
<li>일반 명사, 동사 등의 자연어를 기반으로 작성한다.</li>
<li>이해가 쉽다.</li>
<li>일관성이 떨어진다.</li>
</ol>
<p>*분산시스템을 위한 마스터-슬레이브 아키텍처에 대한 설명
찾아보기...!</p>
<p>*gof 디자인패턴
생성패턴 - 추(추상화:앱스트렉트)빌(빌더)팩(팩토리)프(프로토타입)싱(싱글톤)
구조패턴 - 어(어댑터)브(브릿지)컴(컴포시트)데(데코레이터)퍼(퍼케이드)플(플라이웨이트)프(프록시)
행위패턴 - 나머지
]</p>
<p>*럼바우
!!객동기 외우기!!
-객체:객체 객2
객체(정보 모델링, 시스템에서 요구)
-동적: 상태 동상
동적(제어,흐름,동작)
-기능: 자료 기자
기능(DFD)</p>
<p>*객체지향 분석기법은 상향식 처리방식! 하향식 처리방식은 절차지향분석기법
즉, 객체 지향 분석기법은 동적 모델링, 상향식! 추상화 시키는 작업, 코드 재사용성, 시스템 변경 쉬움</p>
<p>*분산시스템에서 미들웨어는 애플리케이션- 사용자 외에도 서비스 제공가능함. 위치 투명성, 여러 컴포넌트가 요구하는 재사용가능한 서비스 구현, 분산 시스템에서 다양한 부분 관리및 통신, 데이터 교환가능</p>
<p>*소프트 웨이 아키텍처에서 데이터는 파이프를 통해 양방향,단반향으로 흐르고 필터 이동시 오버헤드 발생할 수 있음.</p>
<p>*유저 인터페이스는 직관성, 유효성, 학습성, 유효성 중요! 메세지 이해쉽게 오류의 구체적 설명! 오류로 인해 발생사항은 부정적내용을 사용자에게 알리기! </p>
<ul>
<li>애자일 방법론 특징</li>
<li>프로젝트 요구사항은 기능! 중심</li>
<li>공정과 도구보다 &#39;개인&#39; 과 소통을 중요</li>
<li>&#39;변화&#39;에 유연 신속 대처!</li>
<li>&#39;고객&#39;과 피드백 중요!</li>
</ul>
<ul>
<li>소프트웨어 설계에서 요구사항 분석</li>
</ul>
<p>요구사항 개발 프로세스는 도출-분석-명세-확인 </p>
<ul>
<li><p>소프트웨어 사용시 발견되는 오류 정리 단계는 검증단계임(정형기술검토활용)
정형기술검토활용</p>
</li>
<li><p>동료 검토 : 작성자 내용 직접 설명 후 동료가 결함찾기</p>
</li>
<li><p>워크스루 : 검토회의전 요구사항 명세서 미리 배포 후 짧은 검토 회의를 통해 결함 발견)</p>
</li>
<li><p>인스펙션 : 전문가가 확인해 오류 찾는 것</p>
</li>
<li><p>객체 지향 에서 상위 클래스의 메소드와 속성을 하위클래스가 물려받는건 상속인데 영어로 뭐냐..
상속 (인히리텐스)?
다형성(폴리몰피니즘)
캡슐화(인켑슐레이션)
추상화(엡스트랙션)</p>
</li>
<li><p>설계 기법 중 하향식 설계방법과 상향식 설계 방법
하향식</p>
</li>
<li><p>계층 구조상 주요 컴포넌트 찾은후 낮은 수중의 컴포넌트들로 분해(단계적 정제) ! 메인 모듈 설계-&gt; 단계적으로 구체화</p>
</li>
<li><p>인터페이스 이미 정의되어 있어 통합 간단</p>
</li>
<li><p>레벨 낮은 데이터 구조의 세부사항은 설계초기 단계에서 필요
상향식</p>
</li>
<li><p>기본적 컴포넌트 먼저 설계 후 이를 사용하는 상위 수준의 컴포넌트 설계</p>
</li>
<li><p>최하위 수준에서 모듈들 설계 후 완성되면 이들 결합해 검사함.</p>
</li>
<li><p>기존 컴포넌트를 조합해 시스템을 개발하는 경우 상향식이 적합함</p>
</li>
<li><p>인터페이스가 이미 성립이 되어있어야 기능추가가 쉽기에 꼭 인터페이스 성립을 해줘야한다.</p>
</li>
<li><p>자료 흐름도(DFD) 요소</p>
</li>
<li><p>처리(process) :원</p>
</li>
<li><p>자료흐름(data flow) : 화살표</p>
</li>
<li><p>자료 저장소 (data store) : 평행선</p>
</li>
<li><p>단말 (terminal) :사각형</p>
</li>
<li><p>개발시스템을 이해하기 쉽게 표현해 분석가, 의뢰인, 설계자가 효율적인 의사소통을 할 수 있게 하는 표준화된 모델링 언어 UML</p>
</li>
<li><p>애자일 기법 중 스크럼과 관련된 용어 설명</p>
</li>
<li><p>스크럼 마스터 : 스크럼 프로세스 따르며, 팀이 스크럼을 효과적으로 활용할 수 있게 보장하는 역할</p>
</li>
<li><p>제품 백로그 : 스크럼팀이 해결하는 목록, 소프트웨어 요구사항, 아키텍처 정의 등</p>
</li>
<li><p>속도 : 한번의 스프린트에서 한팀이 어느정도 제품백로그를 감당할 수 있는지 추정치</p>
</li>
<li><p>스프린트 : 개발을 2~4주간 진행하는 과정</p>
</li>
<li><p>백로그에 작성된 테스크를 대상으로 작업시간 측정 후 개발자에게 할당</p>
</li>
</ul>
<p>*UML 다이어그램
-정적 구조 : 클래스, 객체, 패키지, 컴포넌트, 복합구조, 배치
-동적구조: 유스케이스, 상태, 활동, 시퀀스, 통신, 상호작용, 타이밍</p>
<ul>
<li><p>MOM </p>
</li>
<li><p>메서지 기반 비동기형 메시지 전달 방식 미들웨어</p>
</li>
<li><p>온라인 업무보다 이기종 분산데이터 시스템 으로 데이터 동기를 위해 많이 사용 </p>
</li>
<li><p>즉각적 응답보다는 느리지만 안정적 응답을 필요로 할때 주로 사용</p>
</li>
<li><p>익스트림 프로그래밍</p>
</li>
<li><p>소규모 개발 조직이 불확실하고 변경이 많은 요구 접할경우 적절함.</p>
</li>
<li><p>익스트림 프로그래밍을 구동시키는 원리는 상식적 원리와 경험을 최대한 끌어올리는 것</p>
</li>
<li><p>구체적 실펀방법을 정의, 개발문서보다 소스코드에 중점</p>
</li>
<li><p>애자일 방법론</p>
</li>
<li><p>반복적 점진적 개발을 강조해 변화에 유연하게 대응할 수 있도록 설계된 방법론</p>
</li>
<li><p>component</p>
</li>
<li><p>프로그래밍에 있어 재사용이 가능한 각각의 독립된 모듈</p>
</li>
<li><p>특정기능 수행을 위해 독립적으로 분리한것</p>
</li>
</ul>
<p>*구조적 방법론?
-계획중심 접근방식</p>
<ul>
<li><p>소프트 웨어 설계에서 자주 발생하는 문제에대한 일반적이고 반복적인 해결방법(디자인패턴)</p>
</li>
<li><p>객체지향 분석기법 </p>
</li>
<li><p>럼바우 방법: 그래픽 표기법을 이용하여 모델링
부치 방법: 미시적 개발프로세스와 거시적 개발 프로세스를 모두 사용하는 분석방법</p>
</li>
<li><p>제콥슨방법: 유스케이스를 강조하여 사용하는 분석방법 클래스와 객체들 분석 및 식별, 클래스 속성과 연산 정의</p>
</li>
<li><p>코드와 유리든 : E-R다이어 그램사용하여 객체 행위 모델링, 객체식별, 구조식별,주제정의,송성과 인스턴스 연결정의, 연산과 메세지 연결정의등 과정으로 구성</p>
</li>
<li><p>와이어퍼스블록 방법: 분석과 설계간 구분없고 고객명세서 평가해 설계까지 연속 수행기법</p>
</li>
<li><p>EAL(enterprise applixation integration) : 기업 응용 프로그램 통합 기업용응용프로그램의 구조적 통합방안
FEP(fornt-end-process : 입력되는 데이터를 컴퓨터 프로세서가 처리전 미리 처리해 시간 줄여주는 것
GPL(general public license): 자유소프트웨어 재단에서 만든 자유소프트웨어 라이선스
Duplexing :이중화 쌍방향 통신 (두지점사이에서 정보를 주고 받는 전자통신시스템)</p>
</li>
<li><p>객체 지향 개념</p>
</li>
<li><p>메서드 : 클래스로부터 생성된 객체 사용방법, 객체가 메서지 받아 실행해야하는 객체의 구체적연산</p>
</li>
<li><p>메세지 : 객체간 상호작용하기 위한 수단, 객체에게 어떤 행위를 하도록 지시방법</p>
</li>
<li><p>클래스 : 특정 객체 내 변수와 메서드 정의하는 일종의 틀, 객체 지향 프로그래밍에서 데이터 추상화하는 단위</p>
</li>
<li><p>필드 : sql에서 열또는 속성으로 불리는 것</p>
</li>
<li><p>피드백 
: ul와 관련된 기본개념 중 하나, 처리된 결과를 측정하고 목표에 도달되었는가를 검사하며 불충분할 경우 다시 입력하는 요소 </p>
</li>
</ul>
<hr>
<p>정처기 2과목</p>
<ol>
<li>인터페이스 보안을 위해 네트워크 영역에 적용될 수 있는 솔루션</li>
</ol>
<p>IPsec(IP security) : 네트워크 계층에서 IP 패킷 단위의 데이터 변조 방지 및 은닉 기능을 제공하는 프로토콜;
SSL(Secure Sockets Layer) : TCP/IP 계층과 애플리케이션 계층 사이에서 인증, 암호화, 무결성을 보장하는 프로토콜;
S-HTTP(Secure Hypertext Transfer Protocol) : 클라이언트와 서버 간에 전송되는 모든 메시지를 암호화 하는 프로토콜;</p>
<p>SMTP: 이메일 송수신!</p>
<p>2.반규정화는? 처리량 감소, 속도향상을 위해 저장공간 투자하는것</p>
<p>[집중이부진]
집계테이블(계산미리수행), 
중복테이블(서버분리,업무구별), 
이력테이블(레코드중복저장), 
부분테이블(접근시도가 많은 자료모으기), 
진행테이블(A에 접근하기 위해 다수의 테이블 거칠경우 간소화)</p>
<ol start="3">
<li>ISO/IEC 9126 하위특성 기능성,신뢰성, 사용성 효율성, 유지보수성 ,이식성</li>
</ol>
<ul>
<li>기능성 : 적합성, 정확성, 상호 운용성, 보안성, 준수성</li>
<li>신뢰성 : 성숙성, 결함허용성, 복구성</li>
<li>사용성 : 이해성, 학습성, 운용성, 준수성</li>
<li>효율성 : 시간반응성, 자원효율성, 준수성</li>
<li>유지성 : 분석성, 변경성, 안정성, 시험성, 준수성</li>
<li>이식성 : 적응성, 설치성, 공존성, 대체성, 준수성</li>
</ul>
<ol start="4">
<li><p>트리의 차수와 단말노드
트리의 차수? 전체 트리에서 가장 큰 차수
단말 노드 ? 자식이 없는 차수
차수? 특정 노드에 연결된 자식 노드의 수 만약 특정 노드 언급이 없을 때 가장 큰 차수가 가지는 값 
노드 : 자식이 없는 노드 </p>
</li>
<li><p>디지털 저작권 관리 (DRM)의 기술 요소</p>
<ul>
<li>암호화(Encryption) : 콘텐츠 및 라이선스를 암호화하고 전자 서명을 할 수 있는 기술</li>
</ul>
</li>
</ol>
<ul>
<li>키 관리(Key Management) : 콘텐츠를 암호화한 키에 대한 저장 및 분배 기술</li>
<li>암호화 파일 생성(Packager) : 콘텐트를 암호화된 콘텐츠로 생성하기 위한 기술</li>
<li>식별 기술(Identification) : 콘텐츠에 대한 식별 체계 표현 기술</li>
<li>저작권 표현(Right Expression) : 라이선스의 내용 표현 기술</li>
<li>정책 관리(Policy Management) : 라이선스 발급 및 사용에 대한 정책 표현 및 관리 기술</li>
<li>크랙 방지(Tamper Resistance) : 크랙에 의한 콘텐츠 사용 방지 기술</li>
<li>인증(Authentication) : 라이선스 발급 및 사용의 기준이 되는 사용자 인증 기술</li>
</ul>
<ol start="6">
<li>소프트웨어 테스트 법칙</li>
</ol>
<ul>
<li>파레토 법칙 :오류의 80%는 전체의 20%내에서 발견된다는 법칙</li>
<li>Brooks의 법칙 : 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어짐
(이 두가지가 가장 많이 나왔음)</li>
</ul>
<p>6-1 소프트웨어 테스트 기본 원칙</p>
<ul>
<li>살충제 패러독스: 동일한 테스트 케이스로 반복 실행하면 더이상 새로운 결함을 발견할 수 없으므로 주기적으로 테스트 케이스를 점검하고 개선해야 한다.</li>
<li>오류 부재의 궤변: 사용자의 요구사항을 만족하지 못한다면 오류를 발견하고 제거해도 품질이 높다고 말할 수 없다.</li>
<li>결함 집중 : 애플리케이션 결함의 대부분은 소수의 특정한 모듈에 집중되어 존재함. 결함은 발생한 모듈에서 계속 추가로 발생할 가능성이 높음 (파레토법칙 좌우)</li>
</ul>
<ol start="7">
<li>소프트 웨어 형상 관리의 의미</li>
</ol>
<ul>
<li>소프트웨어의 변경 사항을 체계적으로 추적하고 통제하는 것(단순 버전 관리보다 더 포괄적인 개념
즉, 소프트웨어에서 일어나는 수정이나 변경을 알아내고 제어하는 것을 의미한다. </li>
<li>소프트웨어 개발의 전체 비용을 줄이고, 개발 과정의 여러 방해 요인이 최소화되도록 보증하는 것을 목적으로 한다. </li>
<li>형상관리를 위하여 구성된 팀을형상통제위원회(CCB; Change Control Board)이라고 한다. </li>
<li>형상관리의 기능 중 하나는 버전 제어 기술이다. </li>
</ul>
<p>형상 관리 절차: 형상 식별 -&gt; 형상 통제 -&gt; 형상 감사 -&gt; 형상 기록/보고</p>
<p>형상 식별</p>
<ul>
<li>형상 관리의 대상들을 구분하고 관리 목록의 번호를 정의하여 부여하는 과정</li>
<li>형상 관리 대상: 품질관리 계획서, 품질관리 매뉴얼, 요구 사항 명세서, 설계/인터페이스 명세서, 테스트 설계서, 소스코드</li>
</ul>
<p>형상 통제</p>
<ul>
<li>소프트웨어 형상 변경 제안을 검토, 현재 소프트웨어 기준선(Baseline)에 반영하도록 통제</li>
<li>형상 통제가 이루어지기 위해서는 형상 통제 위원회(Configuration Control Board, CCB)의 승인을 통한 변경 통제가 이루어짐</li>
</ul>
<p>형상 감사</p>
<ul>
<li>형상 항목의 변경이 계획에 따라 제대로 이뤄졌는지를 검토/승인하는 것</li>
<li>개발자, 유지보수 담당자가 아닌 제 3자의 객관적인 확인 및 검증 과정을 통해 새로운 형상의 무결성을 확보하는 활동</li>
</ul>
<p>형상 기록/보고</p>
<ul>
<li>소프트웨어 개발 상태에 대한 보고서를 제공하는 것</li>
<li>베이스라인 산출물에 대한 변경과 처리 과정에서의 변경을 상태 보고에 모두 기록</li>
</ul>
<p>7-1. 형상관리 도구의 주요 기능
소프트웨어 버전 등록 관련 주요 용어</p>
<ul>
<li>저장소(Repository) : 최신 버전의 파일들과 변경 내역에 대한 정보들이 저장되어 있는 곳</li>
<li>가져오기(Import) : 버전 관리가 되고 있지 않은 아무것도 없는 저장소에 처음으로 파일을 복사</li>
<li>체크아웃(Check-Out) : 프로그램을 수정하기 위해 저장소에서 파일을 받아 옴. 소스 파일과 함께 버전 관리를 위한 파일들도 받음</li>
<li>체크인(Check-In) : 체크아웃 한 파일의 수정을 완료한 후 저장소의 파일을 새로운 버전으로 갱신</li>
<li>커밋(Commit) : 체크인을 수행할 때 이전에 갱신된 내용이 있는 경우 충돌을 알리고 diff 도구를 이용해 수정 후 갱신 완료</li>
<li>동기화(Update) : 저장소에 있는 최신 버전으로 자신의 작업 공간을 동기화함 </li>
</ul>
<ol start="8">
<li>알고리즘 시간 복잡도</li>
</ol>
<ul>
<li>O(1) : 비례하지 않는 (항상 일정한)</li>
<li>O(log2^n) : 로그에 비례하는</li>
<li>O(n) :정비례하는(선형-&gt; 검색효율이 최악)</li>
<li>O(nlog2^n) : 로그*변수에 비례하는(선형 로그)</li>
<li>O(n^2) :  제곱에 비례하는</li>
<li>O(n^3) : 세제곱에 비례하는</li>
<li>O(2^n) : 지수에 비례하는</li>
<li>O(n!) : 팩토리얼에 비례하는</li>
</ul>
<p>여기서
0(1) : 상수형 복잡도 (해시함수)
0(logN) : 로그형 복잡도 (이진 탐색)
0(N) : 선형 복잡도 (순차탐색)
0(Nlog2N) : 선형 로그형 복잡도 (퀵 정렬, 병합정렬)
-&gt; 로그,변수에 비례/ 문제 해결에 필요한 단계가 그 만큼 수행되는것
0(N^2) : 제곱형(거품(버블)정렬, 삽입정렬, 선택정렬,쉘정렬,퀵정렬)
-&gt;제곱에 비례
문제해결에 필요한 단계가 입력값(N)의 제곱만큼 수행되는 것 
그래서 정렬된 데이터는 버블정렬과 삽입정렬은 o(N)이 될 수 있음.</p>
<ol start="9">
<li>소스코드 품질분석 도구</li>
</ol>
<ul>
<li>정적분석도구
pmd: 소스 코드에 대한 미사용 변수 최적화 안된 코드 등 결함을 유발할 수 있는 코드 검사
cppcheck: C/C++ 코드에 대한 메모리 누수 오버플로우 등 분석
ConarQube: 중복 코드 복잡도 코딩 설계 등을 분석하는 소스 분석 통합 플랫폼
checkstyle: 자바 코드에 대해 소스코드 표준을 따르고 있는지 검사
ccm: 다양한 언어의 코드 복잡도를 분석
cobertura: 자바 언어의 소스코드 복잡도 분석 및 테스트 커버리지 측정</li>
<li>동적분석도구
Avalanche : Valgrind 프레임워크 및 STP기반 / 프로그램 결함 및 취약점 분석
valgrind : 프로그램 내에 존재하는 메모리 및 쓰레드 결함 분석</li>
</ul>
<ol start="10">
<li>검증 검사 기법</li>
</ol>
<p>-동치 분할 검사 : 입력자료에 초점을 맞춰 케이스를 만들고 검사하는 방법</p>
<p>그중 인스 테스트의 종류
-알파테스트 : 개발자의 장소에서 사용자가 개발자 앞에서 행하는 테스트 기법
-베타 테스트 : 선정된 최종 사용자가 여러명의 사용자 앞에서 행하는 테스트 기법</p>
<ul>
<li>사용자 인수 테스트</li>
<li>운영상의 인수 테스트</li>
<li>규정 인수 테스트
가 있음.</li>
</ul>
<ol start="11">
<li><p>형상 검사?
구성 검토 검사인데 구성요소, 목록, 유지보수를 위한 모든 사항이 표현되었는가를 검사 </p>
</li>
<li><p>애플리케이션 통합 테스트 유형</p>
</li>
</ol>
<p>하향식 통합 (Stub)</p>
<ul>
<li>상위 컴포넌트 테스트를 하고 점증적으로 하위 컴포넌트를 테스트 하는 것</li>
<li>하위 컴포넌트 개발이 완료되지 않으면 스텁을 사용함</li>
<li>깊이 우선 방식, 너비 우선 방식
상향식 통합(Driver) </li>
<li>프로그램의 하위 모듈에서 상위 모듈 방향으로 통합하면서 테스트</li>
<li>하나의 주요 제어 모듈과 관련된 종속 모듈의 그룹인 클러스터 필요</li>
<li>상위 모듈 개발이 완료되지 않은 경우 드라이버를 사용함.</li>
</ul>
<p>회귀 테스트 </p>
<ul>
<li>이미 테스트된 프로그램의 테스팅 반복</li>
<li>통합 테스트로 인해 변경된 모듈이나 컴포넌트에 새로운 오류가 있는지 확인</li>
</ul>
<p>빅뱅테스트
-통합테스트 중 비점진적 통합방식</p>
<ol start="13">
<li>SW 패키징 도구용 시 고려 사항</li>
</ol>
<ul>
<li>사용자 운영체제, CPU,메모리 등 필요한 최소환경 정의</li>
<li>UI는 편의성, 직관성을 고려하고 매뉴얼과 일치시켜 패키징</li>
<li>소프트웨어와 하드웨어가 함께 관리될 수 있도록 Managed Service형태로 제공</li>
<li>암호화, 모듈화 하여 배포(다양한 기종에서 사용 가능하게)</li>
</ul>
<ol start="14">
<li><p>외계인 코드?
외계인은 없는 존재를 뜻하고 즉, 코드에 대해 아는 사람이 없다는 것이다. 그래서 유지보수가 어려운 코드를 말한다.</p>
</li>
<li><p>스파게티 코드?
프로그램의 로직이 복잡하여 이해하기 어려운 프로그램을 의미함(나쁜코드..)</p>
</li>
</ol>
<p>16 . 소프트웨어 테스팅 중 화이트박스테스팅 (White Box Testing)과 블랙박스테스팅(Black Box Testing)</p>
<p>White Box Testing? 내부 구조와 동작을 검사하는 테스트 방식, 소프트웨어 내부 소스를 테스트, 내부의 모든 경로를 테스트하여 테스트 케이스를 설계한다.
-&gt; 이건 &#39;내부 소스코드;를 테스트하는 기법이기에 개발자 관점의 단위 테스트로 생각하면 됨.</p>
<ul>
<li>기초 경로 검사(Base Path Testing), </li>
<li>제어 구조검사(Control Structure Testing),</li>
<li>조건검사(Condition Testing),</li>
<li>루프검사(Loop Testing),
-데이터 흐름 검사(Data Flow Testing)</li>
</ul>
<p>화이트박스 테스트 기법</p>
<ul>
<li>문장검증 : 프로그램의 모든 문장이 적어도 한번씩 수행되는 검증 기준</li>
<li>선택검증 : 선택하는 부분만 검증</li>
<li>경로검증 : 수행 가능한 모든 경로 검사</li>
<li>조건검증 : 문장 내 조건식을 조사하는 기준</li>
</ul>
<p>Black Box Testing? 내부 구조나 작동 원리를 모르는 상태에서 입력에 따른 출력 결과를 테스트
따라서, 경계값을 분석할수 있고, 기능을 테스트할 수 있고, 프로그램 구조를 고려하지 않는다.
-&gt;이건 사용자 관점의 테스트이며, 작동원리를 모르는 상태에서 동작을 검사하는 방식이라고 생각하면 됨!</p>
<ul>
<li>동치(동등)분할검사 (Equivalence Partitioning Testing) </li>
<li>경계값 분석(Boundary Value Testing)</li>
<li>원인-효과 그래프 검사(Cause-Effect Graphing Testing)</li>
<li>오류 예측 검사(Error Guessing) </li>
<li>비교 검사(Comparison Testing)</li>
</ul>
<ol start="17">
<li>소프트 웨어 품질 측정 개발자 관점</li>
</ol>
<ul>
<li>무결성(integrity): 시스템이 프로그램이나 데이터에 대한 허용되지 않거나 잘못된 접근을 막는 정도. 무결성의 기본 개념에는 데이터의 적절한 접근을 보장할 뿐만 아니라 권한이 없는 사용자의 접근 제한 기능이 포한된다. 즉, 병렬 데이터를 갖는 데이블은 병렬로 변경되고 날짜 필드는 타당한 날짜만을 포함하는 식이다.</li>
<li>신뢰성(reliability): 정해진 상황에서 언제든지 필요한 기능을 수행할 수 있는 시스템의 능력 - 고장 사이의 시간</li>
<li>사용용이성(=유용성)(usability): 사용자가 시스템을 배우고 사용하는 데 있어서의 용이함</li>
<li>효율성(efficiency): 메모리와 실행 시간 같은 시스템 리소스의 최소 사용</li>
<li>정확성(correctness): 시스템의 사양과 설계, 구현에 있어서 오류가 없는 정도</li>
<li>적응성(adaptablility): 시스템을 변경하지 않고 설계된 환경에서 뿐만 아니라 다른 응용 분야나 환경에서도 사용될 수 있는 정도</li>
<li>정밀성(accuracy): 구성된 시스템에 오류가 없는 정도. 특히 대량의 데이터를 고려한다. 정밀성은 정확성과 다르다. 정밀성은 시스템이 정확하게 구성되었는지가 아닌 시스템이 용도대로 얼마나 잘 수행하는지를 결정한다.</li>
<li>견고성(robustness): 시스템이 잘못된 입력이나 악조건에서도 기능을 계속해서 수행할 수 있는 정도</li>
</ul>
<ol start="18">
<li><p>인터페이스 구현 검증 도구 (잘봐아)
xUnit : Java, C++ 등 다양한 언어 지원하는 단위 테스트 프레임워크
STAF : 서비스 호출 및 컴포넌트 재사용 등 환경 지원하는 테스트 프레임워크
FitNesse : 웹 기반 테스트케이스 설계, 실행, 결과 확인 등을 지원하는 테스트 프레임워크
NTAF : FitNesse의 장점인 협업 기능과  STAF의 장점인 재사용 및 확장성을 통합한 네이버의 테스트 자동화 프레임워크이다.
Selenium : 다양한 브라우저 및 개발 언어 지원하는 웹 애플리케이션 테스트 프레임워크
Watir : Ruby를 사용하는 애플리케이션 테스트 프레임워크
Ruby : 인터프리터 방식의 객체지향 스크립트 언어</p>
</li>
<li><p>EAI(Enterprise Application Integration)의 구축 유형
정의 : 기업 내 각종 애플리케이션 및 플랫폼 간의 정보 전달 연계 통합등 상호연동이 가능하게 해주는 솔루션</p>
</li>
</ol>
<p>Point - to - Point : 가장 기본적인 애플리케이션 통합 방식 1:1로 연결
Hub &amp; Spoke : 단일 접점인 허브 시스템을 통해 데이터 전송하는 중앙 집중형 방식
(미들웨어를 둘수도 두지않을수도 있음)
Message Bus : 애플리케이션 사이에 미들웨어를 두어 처리하는 방식
Hybrid : Hub &amp; Spoke 와 Message Bus 혼합 방식
\Hybrid에 대한 설명
(1) Hub &amp; Spoke와 Message Bus의 혼합방식이고!
(2)필요한 경우 한 가지 방식으로 EAI구현이 가능하고 
(3)데이터 병목현상을 최소화할 수 있고
(4)중간에 미들웨어를 둔다.</p>
<ol start="20">
<li>트리 순회 방법 
전위(Preorder)순회 : 루트를 먼저 방문 Root-&gt;Left-&gt;Right 
중위순회(Inorder) : 왼쪽 하위트리를 방문한 뒤 루트를 방문 Left-&gt;Root-&gt;Right 
후위순회(Postorder) : 하위트리를 방문한 뒤 루트를 방문  Left-&gt;Right -&gt;Root
&lt;이진트리 운행법)
Preorder 운행 :  Root-&gt;Left-&gt;Right 
Inorder 운행 :  Left-&gt;Root-&gt;Right 
Postorder 운행 : Left-&gt;Right -&gt;Root</li>
</ol>
<p>(이거 잘 이해가 안되서 ... 다시 봐야할듯)</p>
<p>비슷하게 연산식에 적용하면???</p>
<p>PreFix(전위표기식)
root(연산자)-&gt;left(피연산자)-&gt;right(피연산자)
Infix (중위표기식)
left(피연산자)-&gt;root(연산자)-&gt;right(피연산자)
Postfix (후위표기식)
left(피연산자)-&gt;right(피연산자)-&gt;root(연산자)</p>
<p>3 4 * 5 6 * + =&gt;
(34<em>)(56</em>)(+)
12+30</p>
<ol start="21">
<li>소프트 웨어 공학의 기본 원칙 </li>
</ol>
<ul>
<li>품질높은 소프트 웨어 상품 개발</li>
<li>지속적인 검증 시행</li>
<li>결과에 대한 명확한 기록 유지</li>
</ul>
<ol start="22">
<li>클린코드 작성원칙</li>
</ol>
<ul>
<li>가독성 : 누구든지 코드를 쉽게 읽을 수 있도록 작성, 코드 작성 시 이해하기 쉬운 용어를 사용하거나 들여쓰기 기능 등을 사용</li>
<li>단순성 : 코드를 간단하게 작성, 한 번에 한 가지를 처리하도록 코드를 작성하고 클래스/메소드/함수 등을 최소 단위로 분리</li>
<li>의존성배제 : 코드가 다른 모듈에 미치는 영향을 최소화, 코드 변경 시 다른 부분에 영향이 없도록 작성 </li>
<li>중복성 최소화 : 코드의 중복을 최소화, 중복된 코드는 삭제하고 공통된 코드를 사용</li>
<li>추상화 : 상위(부모,슈퍼) 클래스/메소드/함수에서는 간략하게 애플리케이션의 특성을 나타내고, 상세 내용은 하위(자식,서브) 클래스/메소드/함수에서 구현</li>
</ul>
<ol start="23">
<li>알고리즘 설계 기법 (31번)
Divide and Conquer(분할 정복 알고리즘) : 그대로 해결할 수 없는 문제를 작은 문제로 분할하여 문제를 해결하는 알고리즘
Greedy(탐욕 알고리즘) : 현재 시점에서 가장 최적의 방법을 선택하는 알고리즘
Backtracking : 가능성이 없는 경우의 수는 가지치기를 하고 진행되는 알고리즘이다
brute force 알고리즘 (완전탐색 알고리즘): 모든 조합을 시도하여 문제의 답을 찾는 알고리즘</li>
</ol>
<ol start="24">
<li>제품 소프트웨어의 형상관리 </li>
</ol>
<ul>
<li>이전리버전, 버전에 대한 정보에 접근 가능하여 배포본 관리에 유용하게 하기</li>
<li>불필요한 사용자의 소스 수정을 제한하기</li>
<li>동일한 프로젝트에 대해 여러개발자가 동시에 개발이 가능하게 하기</li>
<li>소프트웨어에 가해지는 변경을 제어하고 관리함.</li>
<li>유지보수 단계 뿐만 아니라 개발단계에서도 적용가능</li>
<li>프로젝트 계획, 분석서, 프로그램, 테스트 케이스 모두 관리대상임.</li>
</ul>
<p>대표적인 형상 관리 도구 
GIT,CVS, Subversion 등 </p>
<ol start="26">
<li>제품 소프트 웨어 패키징 도구 활용시 고려할 점</li>
</ol>
<ul>
<li>반드시 내부 콘텐츠에 대한 암호화 및 보안 고려</li>
<li>여러가지 이기종 콘텐츠 및 단말기 간 DRM연동 고려 </li>
<li>사용자 입장에서 불편해질 수 있는 문제를 고려해 최대한 효율적으로 적용시킴(복잡성, 비효율성문제 고려)</li>
<li>제품 소프트웨어의 종류에 맞는 알고리즘 선택해 배포시 범용성에 지장없도록 고려</li>
</ul>
<ol start="27">
<li>소프트웨어와 관련, 기본적으로 설명되어야 할 항목들
소프트웨어 개요 / 설치관련파일 / 설치 아이콘 / 프로그램 삭제 / 관련추가정보 </li>
</ol>
<ol start="28">
<li>인터페이스 구현시 사용하는 기술</li>
</ol>
<ul>
<li>ajax : 자바스크립트를 사용한 비동기 통신 기술로 클라이언트와 서버간에 xml 데이터를 주고 받는 기술</li>
<li>procedure : 절차형 SQL을 활용하여 특정 기능을 수행하는 일종의 트랜잭션 언너</li>
<li>Trigger : 데이터의 삽입, 갱신, 삭제 등의 이벤트가 발생할 때 마다 관련 직업이 자동으로 수행되는 절차형 SQL</li>
</ul>
<ol start="29">
<li>소프트 웨어 재공학이 소프트 웨어의 재개발에 비해 갖는 장점</li>
</ol>
<ul>
<li>위험부담 감소</li>
<li>비용절감</li>
<li>시스템 명세의 오류엊게 </li>
<li>개발시간 절약</li>
</ul>
<ol start="30">
<li><p>스키마
외부 스키마 : 개인 또는 응용 개발자 입장에서 보는 데이터베이스
개념 스키마 : 모든 응용 프로그램 또는 사용자들이 필요로 하는 조직 전체 데이터베이스로 단 하나만 존재한다. 
내부스키마 : 물리적 저장장치 </p>
</li>
<li><p>정점이 n개인 무방향 그래프에서 최대의 간선수?  n(n-1)/2개
정점이 n개인 그래프에서 최대 간선수?  n(n-1)개</p>
</li>
<li><p>소프트 웨어 테스트관련 </p>
</li>
</ol>
<p>-테스트 케이스 : 구현된 소프트웨어가 사용자의 요구사항을 정확하게 준수했는지를 확인하기 위해 설계된 입력 값, 실행 조건, 기대 결과 등으로 구성된 테스트 항목에 대한 명세서</p>
<p>그렇다면?
*테스트 케이스의 구성요소</p>
<p>식별자(항목 식별자, 일련번호)
테스트항목(테스트 대상-모듈 또는 기능)
입력 명세(입력 데이터 또는 테스트 조건)
출력 명세(테스트 케이스 수행 시 예상되는 출력 결과)
환경 설정(필요한 하드웨어나 소프트웨어의 환경)
특수 절차 요구(테스트 케이스 수행 시 특별히 요구되는 절차)
의존성 기술(테스트 케이스 간의 의존성)</p>
<p>-테스트 시나리오 : 테스트 케이스를 적용하는 순서에 따라 여러 개의 테스트 케이스들을 묶은 집합
-테스트 오라클 : 테스트의 결과가 참인지 거짓인지를 판단하기 위해 사전에 정의된 참값을 입력하여 비교하는 기법 및 활동
참, 샘플링, 휴리스틱, 일관성 검사가 존재함</p>
<ol start="33">
<li><p>디지털저작권 관리(DRM) 구성요소
콘텐츠 제공자(Contents Provider):콘텐츠를 제공하는 저작권자
콘텐츠 분배자(Contents Distributor):암호화된 콘텐츠를 유통하는 곳이나 사람 (플레이 스토어, 앱스토어 생각하면 될 듯)
클리어링 하우스(Clearing House):저작권에 대한 사용 권한, 라이센스 발급, 암호화된 키 관리, 사용량에 따른 결제 관리 등을 수행
DRM 컨트롤러(DRM Controller): 배포된 콘텐츠의 이용권한을 통제하는 프로그램
패키저(Packager):콘텐츠를 메타 데이터와 함계 배포 가능한 형태로 묶어 암호화하는 프로그램</p>
</li>
<li><p>빌드 자동화 도구
빌드 자동화 도구는?</p>
</li>
</ol>
<ul>
<li>빌드를 포함하여 테스트 및 배포를 자동화하는 도구</li>
<li>Ant, Make, Maven, Gradle, Jenkins 등이 있음</li>
</ul>
<p>Jenkins</p>
<ul>
<li>JAVA 기반의 오픈소스 형태</li>
<li>서블릿 컨테이너에서 실행되는 서버 기반 도구</li>
<li>친숙한 Web GUI 제공</li>
<li>분산 빌드나 테스트 가능</li>
</ul>
<p>Gradle</p>
<ul>
<li>Groovy를 기반으로 한 오픈 소스 형태</li>
<li>안드로이드 앱 개발 환경에서 사용</li>
<li>행할 처리 명령들을 모아 태스크(Task)로 만든 후 태스크 단위로 실행</li>
</ul>
<ol start="35">
<li><p>해싱함수  방법
폴딩법 : 해싱함수  중 레코드 키를 여러부분으로 나누고 나눈 부분의 각 숫자를 더하거나 XOR한 값을 홈 주소로 사용
제산법 : 레코드키를 해시표로 나눈 나머지를 홈 주소로 사용
기수변환법 : 키 숫자의 진수를 다른 진수로 변환시켜 주소 크기를 초과한 높은 자릿수 절단, 다시 주소 범위에 맞게 조정
숫자분석법 : 키 값을 이루는 숫자의 분포를 분석하여 비교적 고른 자리를 필요한 만큼 선택</p>
</li>
<li><p>자료구조 </p>
</li>
</ol>
<p>스택이란?
-한쪽 끝으로만 삽입, 삭제 작업이 이루어짐.
그래서 입출력이 한쪽 끝으로만 제한되어 있는 리스트이다.</p>
<ul>
<li><p>가장 나중에 삽입된 자료가 가장 먼저 삭제되는 후입선출(LIFO) 즉, Last In – First out 처리를 수행한다.</p>
</li>
<li><p>서브루틴 호출, 인터럽트 처리, 수식 계산 및 수식 표기법에 응용된다.</p>
</li>
<li><p>더이상 데이가 없는데 삭제하려고 하면 Underflow가 발생하고,</p>
</li>
<li><p>스택이 가득찼는데 넣을 경우 Overflow가 발생한다.</p>
</li>
<li><p>Top과 Bottom 2개로 이루어져 있음</p>
</li>
<li><p>선형 구조</p>
</li>
</ul>
<p>Queue?큐?
-한쪽에서는 삽입 작업, 다른 한쪽에서는 삭제 작업이 이루어짐. 즉, First In – First Out 처리를 수행한다</p>
<ul>
<li>가장 먼저 삽입된 자료가 가장 먼저 삭제되는 선입선출(FIFO)</li>
<li>선형 구조</li>
</ul>
<p>그외 선형 구조 는? 리스트, 데크
비선형 구조 ? 트리, 그래프</p>
<ol start="37">
<li>사용자 인터페이스(UI)요소?</li>
</ol>
<p>-체크박스 : 여러개의 선택상황에서 1개 이상의 값을 선택할 수 있는 버튼
-라디오버튼 : 여러 항목 중 하나만 선택할 수 있는 버튼
-텍스트박스 : 사용자가 데이터를 입력하고 수정할 수 있는 상자
-토글 버튼 : on / off와 같이 둘중 하나의 값을 선택하는 버튼</p>
<ol start="38">
<li>이진 검색 알고리즘
정의 : 전체 파일을 두 개의 서브파일로 분리해가면서 key 레코드를 검색하는 방식</li>
</ol>
<ul>
<li>탐색 효율이 좋고 탐색 시간이 적게 소요된다. </li>
<li>검색할 데이터가 정렬되어 있어야 한다. </li>
<li>비교횟수를 거듭할 때마다 검색 대상이 되는 데이터의 수가 절반으로 줄어든다. </li>
</ul>
<p>피보나치 수열에 따라 다음에 비교할 대상을 선정하여 검색하는 건 피보나치 검색!</p>
<ol start="39">
<li></li>
</ol>
<p>*퀵 정렬
레코드의 많은 자료 이동을 없애고 하나의 파일을 부분적으로 나누어 가면서 정렬하는 방식
*삽입정렬: 가장 간단한 정렬 방식, 이미 순서화된 파일에 새로운 하나의 레코드를 순서에 맞게 삽입시켜 정렬
*쉘 정렬: 삽입정렬 확장 개념, 입력파일을 매개변수값으로 서브파일 구성하고 각 서브파일을 삽입정렬 방식으로 순서 배열하는 과정을 반복하는 정렬
*선택정렬: n개의 레코드 중에서 최소값을 찾아 첫 번째 레코드 위치에 놓고, 나머지 n-1개 중에서 다시 최소값을 찾아 두 번째 레코드 위치에 놓는 방식을 반복하는 정렬
*버블정렬: 주어진 파일에서 인접한 두 개의 레코드 키 값을 비교하여 그 크기에 따라 레코드 위치를 서로 교환하는 정렬 방식
 ex 9,6,7,3,5
Pass 1  9 6 7 3 5  →  6 9 7 3 5  →  6 7 9 3 5  →  6 7 3 9 5  →  6 7 3 5 9
Pass 2  6 7 3 5 9  →  6 3 7 5 9  →  6 3 5 7 9<br>*힙 정렬: 전이진 트리를 이용한 정렬 방식
*2-Way 합병 정렬: 이미 정렬되어 있는 두 개의 파일을 한 개의 파일로 합병하는 정렬 방식 </p>
<p>40.해싱 함수(Hashing Function)의 종류
제산법, 
제곱법, 
중첩법(폴딩법), 
숫자분석법, 
기수 변환법, 
무작위 방법이 있다.</p>
<p>개방 주소법은 해싱충동 시 빈노드에 데이터를 저장하는 방식이고
선형탐색, 제곱탐색, 랜덤탐색, 이중 해싱 등을 아우른다.</p>
<ol start="41">
<li><p>컴파일이란? 사람의 언어를 컴퓨터가 이해할 수 있도록 언어로 바꾸는 과정을 말함.</p>
</li>
<li><p>힙정렬?</p>
</li>
</ol>
<ul>
<li>정렬할 입력 레코드들로 힙을 구성하고 가장 큰 키 값을 갖는 루트 노드를 제거하는 과정을 반복하여 정렬하는 기법</li>
<li>완전 이진트리(complete binary tree)로 입력자료의 레코드를 구성</li>
<li>최적,평균,최악 모두 O(nlog2n)</li>
</ul>
<ol start="43">
<li>단위 테스트</li>
</ol>
<ul>
<li>테스트 코드가 독립적이어야 함으로 각 모듈간의 상호작용은 해당되지 않음</li>
<li>알고리즘 오류에 따른 원치 않는 결과 </li>
<li>탈출구가 없는 반복문의 사용</li>
<li>틀린 계산 수식에 의한 잘못된 결과 </li>
</ul>
<ol start="44">
<li>테스트와 디버그의 목적</li>
</ol>
<ul>
<li>테스트는 오류를 찾는 과정 디버깅은 오류를 수정하는 과정임. 
Coding
→ Testing
→ Error 발생 (== Bug 발견) 
→ Error 수정 (== Debugging)
→ Retesting</li>
</ul>
<ol start="45">
<li>스택을 이용한 연산
중간값에대해 접근할 수 없음. 그래서 선택정렬은 못함</li>
</ol>
<ul>
<li>재귀호출</li>
<li>후위표현(Post-fix expression)의 연산</li>
<li>깊이 우선탐색</li>
</ul>
<ol start="46">
<li>테스트자동화 도구
단위 테스트(Unit Test)
: 하나의 &quot;모듈&quot;을 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트
내부에 존재하는 논리적인 오류를 검출, 기능이 제대로 수행되는지 점검</li>
</ol>
<p>단위테스트의 종류</p>
<ul>
<li>명세 기반 테스트: 주어진 명세를 빠짐없이 테스트 케이스로 구현하고 있는지 확인하는 테스트</li>
<li>구조 기반 테스트: 프로그램 내부 구조 및 복잡도를 검증하는 화이트박스 테스트 시행, 제어 흐름과 조건 결정 등이 목적
성능 테스트 도구(Performance Test Tools) : 애플리케이션의 처리량, 응답시간, 경과시간, 자원 사용률 등 성능 목표 달성 여부 확인</li>
<li>인위적으로 적용한 가상 사용자를 만들어 테스트 수행</li>
</ul>
<hr>
<p>통합 테스트(Integration Test): 모듈을 통합하는 과정에서 &quot;모듈 간의&quot; 호환성을 확인하기 위해 수행되는 테스트
시스템 테스트(System Test): &quot;완전한 시스템&quot;에 대해 수행하는 테스트. 기능적, 비기능적 요구사항을 만족하는지 확인
인수(Acceptance Test): 실제 환경에서 &quot;사용자&quot;가 참여하는 테스트. 요구 분석 명세서에 나타난 사항을 모두 충족하는지, 시스템이 예상대로 동작하는지 사용자의 관점에서 확인</p>
<ol start="47">
<li>소프트웨어 버전 관리도구 방식
1) 분산 저장소 방식 : 하나의 원격 저장소와 개발자 PC의 로컬 저장소에 저장
자신의 로컬 저장소로 복사해 작업, 로컬 저장소에서 우선 반영(commit) 그 후 원격 저장소에 반영(push) , 문제가 생겨도 로컬 저장소의 자료를 이용해 작업 가능,
로컬 저장소에서 작업 및 처리 속도 빠름
2) 공유 폴더 방식 : 로컬 컴퓨터의 공유 폴더에 저장되어 관리
공유폴더의 파일을 자기 pc로 복사 후 이상 유무 확인
3) 클라이언트/서버 방식 : 중앙 시스템(서버)에 저장되어 관리 방식
개발자별로 자신의 pc(클라이언트)로 복사
모든 버전 관리는 서버에서 수행
서버에 문제 생기면 다른 개발자 협업 및 버전 관리 작업 중단</li>
<li>각종 용어
모듈 </li>
</ol>
<p>-규모가 큰 것을 여러 개로 나눈 조각,
-소프트웨어 구조를 이루는 기본적인 단위</p>
<p>모듈이 되기 위한 특징</p>
<ul>
<li>다른 것들과 구별될 수 있는 독립적인 기능을 갖는 단위.</li>
<li>유니크한 이름을 가짐</li>
<li>모듈에서 또 다른 모듈을 호출 가능</li>
<li>다른 프로그램에서도 모듈을 호출할 수 있다.</li>
</ul>
<p>데이터
관찰하고 측정해서 얻은 Value</p>
<p>저장소
데이터를 논리적 구조로 조직화, 혹은 물리적 공간에 구축한것 </p>
<ol start="48">
<li>소프트웨어 품질 목표 
정확성, 신뢰성, 효율성, 무결성, 유지보수 용이성, 사용 용이성, 검사 용이성, 이식성, 상호 운용성, 유연성, 재사용성</li>
</ol>
<p>-이식성(Portability): 다양한 하드웨어 환경에서도 운용 가능하도록 쉽게 수정될 수 있는 능력
-효율성(Efficiency): 최소의 작업으로 요구되는 기능을 수행하는 정도
-사용 용이성(Usability): 소프트웨어를 쉽게 사용할 수 있는 정도
-정확성(Correctness): 사용자의 요구사항을 충족시키는 정도</p>
<ol start="49">
<li>테스트 수행 도구
: 자료 흐름도, 기능 테스트, 입력 도메인 분석, 랜덤 테스트</li>
</ol>
<p>스터브(Stub)와 드라이버(Driver)는 통합 테스트 시 사용되는 것
스터브(Stub)는 하향식 테스트에 사용되는 테스트용 임시 모듈이고, 드라이브(Drive)는 상향식 테스트에 사용되는 테스트 가동기</p>
<ol start="50">
<li>테스트 목적
강도(Stress) 테스트: 과다 정보량을 부과하여 시스템이 정상적으로 작동되는지 검증하는 테스트
회복(Recovery) 테스트 : 시스템에 고의로 실패를 유도하고 시스템이정상적으로 복귀하는지 테스트한다.
성능 테스트 :사용자의 이벤트에 시스템이 응답하는 시간,특정 시간 내에 처리하는 업무량, 사용자 요구에 시스템이 반응하는 속도 등을 테스트한다
안전(Security) 테스트: 부당하고 불법적인 침입을 시도하여 보안시스템이 불법적인 침투를 잘 막아내는지 테스트한다. </li>
</ol>
<p>51.소스코드 정적분석</p>
<ul>
<li>프로그램을 실행 시키지 않고 코드를 분석하는 방법</li>
<li>코드 내에 존재하는 보안 취약점, 잠재적 결함, 위험 등을 발견 가능</li>
<li>규칙과 흐름에 맞게 코드가 올바르게 작성되어 있는지 점검</li>
</ul>
<ol start="52">
<li>소프트웨어 재공학의 주요 활동</li>
</ol>
<p>Analysis: 기존 소프트웨어를 분석하여 재공학 대상을 선정하는 것
Migration: 기존 소프트웨어를 다른 운영체제나 하드웨어 환경에서 사용할 수 있도록 변환하는 작업
Restructuring: 기존 소프트웨어를 향상시키기 위하여 코드를 재구성하는 작업(기능과 외적 동작은 변하지 않음)
Reverse Engineering: 기존 소프트웨어를 분석하여 소스코드를 얻어내는 작업(소스코드로 소프트웨어를 만드는 작업의 역작업) </p>
<ol start="53">
<li><p>프로그래밍 언어의 선정 기준
친밀감, 언어의 능력, 처리의 효율성, 프로그램 구조, 프로그램의 길이, 이식성, 과거의 개발 실적, 알고리즘과 계산상의 난이도, 자료 구조의 난이도, 성능 고려 사항들, 대상 업무의 성격, 소프트웨어의 수행 환경, 개발 담당자의 경험과 지식, 사용자의 요구사항, 컴파일러의 이용 가능성</p>
</li>
<li><p>소프트 웨어 재사용</p>
</li>
</ol>
<p><strong>소프트웨어 재사용함으로써 얻을 수 있는 이점들</strong></p>
<ol>
<li>개발 시간과 비용 단축</li>
<li>소프트웨어 품질 및 생산성 향상</li>
<li>프로젝트 실패 위험 감소</li>
<li>시스템 구축 방법에 대한 지식 공유</li>
</ol>
<p><strong>소프트웨어 재사용함으로써 얻을 수 있는 문제점들</strong></p>
<ol>
<li><p>재사용할 소프트 웨어 선정 필요</p>
</li>
<li><p>시스템에 공통적으로 사용되는 요소 발견 필요</p>
</li>
<li><p>프로그램의 표준화 부족</p>
</li>
<li><p>새로운 개발 방법론 도입이 어려움</p>
</li>
<li><p>재사용을 위한 관리 및 지원 부족</p>
</li>
<li><p>기존 소프트웨어에 재사용 소프트웨어를 추가하기 어려움</p>
</li>
<li><p>NS Chart
NS-Chart(Nassi-Schneiderman Chart)</p>
</li>
</ol>
<ul>
<li>3가지 기본구조만으로 논리를 표현(표준화 가능)</li>
<li>Flow Chart의 최대 단점인 화살표가 표시되지 않음</li>
<li>기본구조의 입구와 출구는 각 하나씩</li>
<li>전체적인 알고리즘을 일목요연하게 볼 수 있음</li>
</ul>
<p>N-S 차트는 논리 기술에 중점을 둔 도형을 이용한 표현 방법으로 박스 다이어그램, Chapin Chart 라고도 한다.</p>
<ul>
<li>GOTO나 화살표를 사용하지 않는다.</li>
</ul>
<ol start="56">
<li>ISO/IEC 25000</li>
</ol>
<ul>
<li>SW 품질 평가 통합 모델</li>
<li>SQuaRE로도 불림</li>
<li>ISO/IEC 9126, ISO/IEC 12119, ISO/IEC 14598의 3개 표준을 통합한 모델</li>
</ul>
<ul>
<li>2500n : 개요 및 품질관리</li>
<li>2501n : 품질모델</li>
<li>2502n : 품질측정</li>
<li>2503n : 품질요구</li>
<li>2504n : 품질평가</li>
<li>2505n : 확장분야</li>
</ul>
<ol start="57">
<li>코드 인스펙션</li>
</ol>
<ul>
<li>결함 뿐만 아니라 모든 것이 표준대로 되어 있는 지 확인하기 위한 검토</li>
<li>표준이나 명세서에 서술한 내용과 비교하여 편차와 에러를 식별하기 위해 산출물을 근거로 수행하는 검사</li>
<li>정적 테스트에 가까움</li>
</ul>
<ol start="58">
<li></li>
<li><p>Critical Path Method(CPM, 임계 경로법) :
네트워크를 중심의 논리적 구성. 시간과 비용 문제를 취급.
프로젝트를 일정 기일 내에 완성시키고 해당 계획이 원가의 최소값에 의해 보증되는 등의 최적 스케줄을 구하는 관리 방법.
(주로 건설과 설계를 포함하는 복잡한 일에 이용되어 효과를 발휘 함.</p>
</li>
<li><p>Risk Analysis : 프로젝트에 내재된 위험 요소를 인식하고 그 영향을 분석하여 이를 관리하는 활동으로서, 프로젝트를 성공시키기 위하여 위험 요소를 사전에 예측, 대비하는 모든 기술과 활동을 포함하는 것</p>
</li>
<li><p>Work Breakdown Structure(업무 분업 구조) :
성과 목표 완전 달성을 위한 프로그램.
산업 관리 간접 부문의 기술 혁신형 업무-목표를 설정하여 소정 기간, 자원 내에서 달성하는 형태의 업무-를 효과적으로 수행하기 위한 수법.</p>
</li>
<li><p>Waterfall Model(폭포수 모델) :
S/W 개발 생명주기에 기반하고 있는 소프트웨어 개발 기법 중 하나.
한 번 떨어지면 다시 거슬러 올라갈 수 없는  폭포수처럼, 각 개발 단계를 확실히 매듭 짓고 다음 단계로 넘어간다는 의미. </p>
</li>
<li><p>정형기술검토(FTR)의 지침</p>
</li>
</ol>
<ul>
<li>오류 검출에 초점을 두고 해결책을 나중으로 미룸(제품 검토의 집중성)</li>
<li>검토를 위한 자료를 사전에 배포하여 검토하도록 한다(사전 준비성)</li>
<li>의견을 제한하되 충분히 받아들인다(의제의 제한성)</li>
<li>안건을 세우면 고수한다(안건 고수성)</li>
<li>논쟁과 반박을 제한한다(논쟁 반박의 제한성)</li>
<li>문제 영역을 공개한다(문제 공개성)</li>
<li>참가자의 수를 제한한다(참가 인원의 제한성)</li>
<li>발견된 오류는 문서화한다(문서성)</li>
</ul>
<ol start="60">
<li></li>
</ol>
<ul>
<li>Selection Sort - 배열 내에서 최소값을 찾은 다음 정렬 되지 않은 맨 앞 값과 교환을 하며 정렬을 해 나아가는 방법 (정렬 시간 복잡도 모두 O(n^2))</li>
<li>Bubble Sort - 왼쪽에서 부터 두 데이터를 비교해서 앞에 있는 데이터가 뒤에 있는 데이터 보다 크면 자리를 바꾸는 정렬 알고리즘(정렬 시간 복잡도 모두 O(n^2))</li>
<li>Insert Sort - 한 개의 값을 추출한 다음 앞쪽으로 비교해서 본인의 자리를 알맞게 찾아가게끔 하는 정렬 방법. 정렬 시간 복잡도는 최상일 경우 O(n), 평균과 최악일 경우 O(n^2)</li>
<li>병합 정렬 - 또한 분할 정복에 기반한 알고리즘으로 리스트를 1 이하인 상태까지 절반으로 자른 다음 재귀적으로 합병 정렬을 이용해서 전체적인 리스트를 합병하는 정렬 과정. O(n log n)
※ n(n-1)/2 = O(n^2)</li>
</ul>
<p>정렬이란? 여러 개의 자료를 순서에 따라 나열하는 방법
8개 종류: [선택, 버블, 삽입, 쉘, 퀵, 힙, 이진병합, 버킷정렬]</p>
<p>61.종류 최상 평균 최악
선택 정렬 O(n) O(n2) O(n2)
버블 정렬 O(n2) O(n2) O(n2)
삽입 정렬 O(n2) O(n2) O(n2)
쉘 정렬 O(n) O(n1.5) O(n2)
퀵 정렬 O(nlog2n) O(nlog2n) O(n2)
힙 정렬 O(nlog2n) O(nlog2n) O(nlog2n)
이진병합 정렬 O(nlog2n) O(nlog2n) O(nlog2n)
버킷 정렬 O(dn) O(dn) O(dn)</p>
<p>62.퀵 정렬: 분할 정복 알고리즘의 하나로, 평균적으로 매우 빠른 수행 속도를 자랑하는 정렬 방법</p>
<ul>
<li>하나의 리스트를 피벗(pivot)을 기준으로 두 개의 비균등한 크기로 분할하고 분할된 부분 리스트를 정렬한 다음, 두 개의 정렬된 부분 리스트를 합하여 전체가 정렬된 리스트가 되게 하는 방법 </li>
</ul>
<hr>
<p>정처기 3과목</p>
<ol>
<li>SQL 분류 중 DDL
DDL(Data Definition Language 데이터 정의어): CREATE, ALTER, DROP, TRUNCATE
DML(Data Manipulation Language 데이터 조작어): SELECT, INSERT, UPDATE, DELETE
DCL(Data Control Language 데이터 제어어): GRANT(권한부여), REVOKE(DCL에 해당하는 권한해제)</li>
</ol>
<p>-&gt; 데이터 베이스 관리자가 데이터 보안, 무결성 유지, 병행 제어, 회복을 하기 위해 DBA가 사용하는 제어용 언어</p>
<p>TCL(Transaction Control Language 트랜잭션 제어어): COMMIT, ROLLBACK, CHECKPOINT</p>
<ol start="2">
<li>데이터 제약조건
개체 무결성 제약 조건 : 기본 키를 구성하는 어떤 속성도 Null값이나 중복값을 가질 수 없다.
릴레이션은 참조할 수 없는 외래키 값을 가질 수 없다.
외래키 값은 참조 릴레이션의 기본키 값과 동일해야 한다.
도메인 무결성 제약 조건 : 주어진 속성 값이 정의된 도메인에 속한 값이어야 한다.
참조 무결성 제약 조건 : 외래키의 값은 Null이거나 참조 릴레이션의 기본키 값과 동일해야 한다.</li>
</ol>
<p>3.뷰(view)
뷰는 사용자에게 접근이 허용된 자료만을 제한적으로 보여주기 위해 하나 이상의 기본 테이블로부터 유도된, 이름을 가지는 가상 테이블이다. 저장장치 내에 물리적으로 존재하지 않지만 사용자에게는 있는 것처럼 간주된다. 
논리적 독립성을 제공하고 있다.</p>
<ol start="4">
<li>데이터 베이스의 논리적 설계(데이터모델링)</li>
</ol>
<p>-현실 세계에서 발생하는 자료를 컴퓨터가 이해하고 처리할 수 있는 물리적 저장장치에 저장할 수 있도록 변환하기 위해 특정 DBMS가 지원하는 논리적 자료 구조로 변환시키는 과정
-개념 세계의 데이터를 필드로 기술된 데이터 타입과 이 데이터 타입들 간의 관계로 표현되는 논리적 구조의 데이터로 모델화
-개념 스키마를 평가 및 정제하고 DBMS에 따라 서로 다른 논리적 스키마를 설계하는 단계(종속적인 논리 스키마)
-트랜잭션의 인터페이스 설계
-관계형 데이터베이스라면 테이블 설계
-특정목표 DBMS에 따른 스키마설계
-스키마의 평가 및 정제</p>
<p>그렇다면? 데이터 베이스 설계단계에서의 트랜잭션 설계단계</p>
<p>-개념적 설계 : 
트랜잭션 모델링/ 독립적인 개념 스키마 모델링/ 개념스키마 설계/ E-R 다이어그램
-논리적 설계 : 트랜잭션 인터페이스 설계/ DBMS에 맞는 논리스키마 설계/ 테이블 설계/ 논리적 매핑/ 스키마 평가 및 정제
-물리적 설계 : 레코드 집중의 분석,설계/ 저장레코드 양식 설계 / 저장 구조 및 액세스 경로 설정</p>
<p>물리적 설계 시 고려사항?
o 어떤 인덱스를 만들 것인지에 대한 고려
o 성능 향상을 위한 개념 스키마의 변경 여부 검토
o 레코드의 크기
o 파일과 구조 저장을 위한 최소한의 공간
o 빈번한 질의와 트랜잭션들의 수행 속도를 높이기 위한 고려사항</p>
<ul>
<li>응답 시간</li>
<li>저장 공간의 효율화</li>
<li>트랜잭션 처리량</li>
</ul>
<ol start="5">
<li>애트리뷰</li>
</ol>
<p>-관계 데이터 모델에서 데이터의 가장 작은 논리적 단위의 값, 이 값은 원자 값만을 허용한다.
-같은 타입의 모든 원자 값들의 집합을 그 애트리뷰트의 도메인이라고 한다.
-도메인은 같은 도메인의 값들끼리 비교가 허용된다.
-하나의 도메인에 대하여 둘 이상의 애트리뷰트가 정의될 수도 있다.
-한 릴레이션에서는 모든 애트리뷰트들의 이름이 반드시 달라야 한다.
(원자)
②튜플 : 릴레이션을 구성하는 각각의 행을 말한다. 속성의 모임으로 구성된다. 파일 구조에서 레코드와 같은 의미이다. 튜플의 수를 카디널리티(cardinality) 또는 기수, 대응수라고 한다.
(각각의 행)</p>
<p>다형성 - 하나의 객체가 여러 가지 타입을 가질 수 있는 것
(여러가지)</p>
<p>엔티티: 데이터베이스의 논리적 구성요소, 데이터베이스에 표현하려는 유형, 무형의 개체로 정보의 단위
(데이터베이스 형태를 띈 단위)</p>
<ol start="6">
<li>관계 대수 연산</li>
</ol>
<ul>
<li>셀렉트(Select)σ : 릴레이션에서 조건을 만족하는 튜플 반환 / 수평적으로 절단, 행 가져옴</li>
<li>프로젝트(Project)π : 릴레이션에서 주어진 속성들의 값으로만 구성된 튜플 반환 / 수직적으로 절단, 열 선택적 가져옴</li>
<li>조인(Join)⋈ : 공통 속성을 이용해 두개의 릴레이션 튜플들을 연결해 만들어진 튜플 반환</li>
<li>디비전(Division)÷ [R%S] : 릴레이션S의 모든 튜플과 관련있는 릴레이션R의 튜플 반환</li>
</ul>
<ol start="7">
<li>트랜잭션의 특성 </li>
</ol>
<ul>
<li>Durability 영속성 : 성공적으로 완료된 트랜잭션의 결과는 시스템이 고장나더라도 영구적으로 반영되어야 한다.</li>
<li>Consistency 일관성 : 트랜잭션이 그 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 변환한다. </li>
<li>Atomicity 원자성 : 트랜잭션 연산은 데이터베이스에 모두 반영되든지 아니면 전혀 반영되지 않아야 한다.</li>
<li>Isolation 격리성 : 트랜잭션 실행 중 생성하는 연산의 중간 결과를 다른 트랜잭션이 접근 불가하다. </li>
</ul>
<ol start="8">
<li>분산데이터의 목표</li>
</ol>
<ul>
<li>위치투명성(Location Trasparency) 데이터 베이스의 실제 위치를 알 필요 없이 단지 데이터베이스의 논리적인 명칭만으로 엑세스할 수 있음</li>
<li>중복투명성(Replication Transparency) 데이터가 여러 곳에 중복되어 있더라도 사용자는 마치 하나의 데이터만 존재하는 것 처럼 사용 가능, 시스템은 자동으로 여러 자료에 대한 작업 수행</li>
<li>병행투명성(Concurrency Transparency) 다수의 트랜잭션이 동시에 실현되더라도 그 결과는 영향을 받지 않음</li>
<li>장애투명성(Failure Transparency) 트랜잭션, DBMS, 네트워크, 컴퓨터 장애에도 트랜잭션을 정확히 처리함.</li>
</ul>
<ol start="9">
<li><p>E-R모델
요구사항으로부터 얻어낸 정보들을 개체(Entity), 애트리뷰트(Attribute), 관계성(Relation)으로 기술하는 데이터 모델
개체 타입 (사각형)
관계 타입 (마름모) 
속성 타입 (타원)
연결 (선)
다중값 (원두개)</p>
</li>
<li><p>후보키는 유일성, 최소성이며, 슈퍼키는 유일성 , 최소성은 아님.</p>
</li>
<li><p>키 : 레코드 또는 튜플을 확인하기 위해 이용되는 속성값</p>
</li>
</ol>
<p>1) 기본키
*유일성과 최소성을 만족하는 속성을 가지는 후보키 중에 지정된 하나의 키
*중복되는 값, Null 값을 가질 수 없음.</p>
<ul>
<li>값의 변화가 거의 없고 단순한 후보키가 기본키로 적합.</li>
</ul>
<p>2) 슈퍼키
*데이터베이스에서 테이블의 행을 고유하게 식별할 수 있는 속성 or 속성의 집합</p>
<p>3) 외래키</p>
<ul>
<li>관계형 데이터베이스에서 한 테이블 속성 집합이 다른 테이블의 기본키가 됨.</li>
<li>데이터베이스 내에 존재하는 테이블들의 관계에서 참조의 무결성을 보장하기 위함임</li>
<li>중복되는 값, 비어있는 값(Null) 가질 수 있음(&lt;-&gt;기본키)</li>
</ul>
<p>4) 후보키</p>
<ul>
<li>유일성과 최소성을 만족하는 속성 or 속성들의 집합</li>
<li>슈퍼키 중 최소성을 만족하는 것이 후보키가 됨.</li>
<li>후보키(candidate key)는 기본키(primary key)로 사용 할 수 있으며, 후보키가 여러개일 경우에는 하나를 지정해 사용.
(지정되지 않은 나머지 후보키 = 대체 키(alternate key))</li>
</ul>
<ol start="12">
<li><p>이행적 함수 종속 관계
a-&gt;b b-&gt;c일때 A-&gt;c 이다.</p>
</li>
<li><p>Distinct는 중복제거임!</p>
</li>
<li><p>데이터 베이스 시스템
트리거 : 데이터페이스가 미리 정해 놓은 조건이 충족되거나, 특정테이블에 삽입, 수정, 삭제 등의 데이터 변경 이벤트가 발생하면 DBMS 에서 자동적으로 실행되도록 구현한 프로그램
[해설작성자 : G다다]</p>
</li>
</ol>
<p>무결성(integrity) : 데이터의 무결성은 데이터의 정확성, 일관성, 유효성이 유지되는 것을 말한다. 데이터의 무결성을 유지하는 것은 데이터베이스 관리시스템 (DBMS)의 중요한 기능이며, 주로 데이터에 적용되는 연산에 제한을 두어 데이터의 무결성을 유지한다.
잠금(lock) : 삽입, 삭제, 갱신 등의 트랜잭션이 일어나는 동안 DBMS의 테이블, 행이나 열 등의 요소들은 잠기게 된다.
복귀(rollback) : 작업 중 문제가 발생되어 트랜잭션의 처리과정에서 발생한 변경사항을 취소하는 명령어
*트랜잭션(Database Transaction) : 데이터베이스 관리 시스템 또는 유사한 시스템에서 상호작용의 단위</p>
<ol start="15">
<li>DDL : 
PRIMARY KEY : 기본키 정의 / FOREIGN KEY : 외래키 정의
UNIQUE : 지정 속성은 중복값 가질 수 없음 / NO ACTION : 변화가 있어도 조취를 취하지 않음
CASCADE : 참조 테이블 튜플 삭제 시 관련 튜플 모두 삭제 및 속성 변경 시 속성값 모두 변경
RESTRICTED : 타 개체가 제거할 요소를 참조중이면 제거를 취소
SET NULL : 참조 테이블 변화 시 기본 테이블 관련 속성값 Null로 변경
SET DEFAULT : 참조 테이블 변화 시 기본테이블의 관련 튜플 속성값을 기본값으로 변경
CONSTRAINT : 제약 조건 이름 지정 / CHECK 속성값에 대한 제약 조건 정의</li>
</ol>
<p>DML :
 INSERT INTO ~ VALUES : 튜플 삽입 / DELETE FROM~ WHERE : 튜플 삭제
UPDATE ~ SET ~ WHERE : 튜플 내용 변경 / SELECT<del>FROM</del>WHERE : 튜플 검색
DISTINCT : 중복 튜플 발견 시 그 중 첫번째 하나만 검색 / DISTINCTROW : 중복 튜플 제거 및 하나만 검색 (튜플 전체를 대상으로 검색)
PREDICATE : 검색할 튜플 수 제한 / AS 속성명 정의
ORDER BY : 특정 속성 기준으로 정렬 후 검색할 때 
ASC : 오름차순 / DESC : 내림차순 / 생략 시 오름차순
GROUP BY : 특정 속성 기준 그룹화하여 검색할 때 사용 having절과 같이 사용되어야함 
[해설작성자 : 거상 주작섭]</p>
<p>CLUSTER
이 옵션은 데이터베이스 객체들을 물리적으로 그룹화하기 위한 것으로, 삭제와는 관련이 없다. </p>
<p>SET-NULL
부모 테이블에서 튜플이 삭제될 때, 참조하는 자식 테이블의 외래키 값을 NULL로 설정합니다. 이는 데이터를 유지하면서 외래키 연결만 끊는 방법</p>
<p>RESTRICTED
일반적으로 RESTRICT 옵션은 부모 테이블의 튜플이 자식 테이블에 의해 참조되고 있을 때 삭제를 금지하는 데 사용됩니다. 삭제하려면 먼저 모든 참조가 제거되어야 한다.</p>
<ol start="16">
<li>병행제어의 로킹(Locking) 단위</li>
</ol>
<p>-로킹단위↑ : 로크 수↓, 병행성↓, 오버헤드↓, 공유도↓, 제어기법 간단하여 관리 수월
-로킹단위↓ : 로크 수↑, 병행성↑, 오버헤드↑, 공유도↑, 제어기법 까다로워 관리 복잡</p>
<ul>
<li>데이터베이스 병행 제어를 위해 트랜잭션(transaction)이 접근하고자 하는 데이터를 잠가(lock) 다른 트랜잭션이 접근하지 못하도록 하는 병행 제어 기법이다.</li>
<li>트랜잭션이 어떤 데이터에 접근하고자 할 때 로킹을 수행</li>
<li>로킹이 되어 있는 데이터에는 다른 트랜잭션이 접근할 수 없음</li>
<li>트랜잭션은 로킹이 된 데이터에 대해서만 연산을 수행</li>
<li>로킹 단위: 필드, 레코드, 테이블, 파일, 데이터베이스 모두 로킹 단위가 될 수 있다.</li>
<li>한 번에 로킹 할 수 있는 객체의 크기를 로킹 단위라고 한다.</li>
</ul>
<ol start="17">
<li>릴레이션의 정규형 조건들?!
원부이 결다조</li>
</ol>
<p>1NF(제1정규형) 조건 : 모든 <em>도</em>메인이 원자 값으로만 구성
2NF(제2정규형) 조건 : 기본키가 아닌 속성이 기본키에 대한 완전 함수적 종속을 만족, <em>부</em>분적 함수 종속을 제거한 정규형
3NF(제3정규형) 조건 : 기본키가 아닌 모든 속성이 기본키에 대해 <em>이</em>행적 함수 종속 관계를 만족하지 않는 정규형
BCNF 조건 : 모든 <em>결</em>정자가 후보키인 정규형, 종속성 보존X
4NF(제4정규형) 조건 : <em>다</em>치 종속이 성립하는 경우, R의 모든 속성이 A에 함수적 종속 관계를 만족
5NF(제5정규형) 조건 : 모든 <em>조</em>인 종속이 R의 후보키를 통해서만 성립되는 정규형</p>
<ol start="18">
<li>저장 레코드 양식 설계 시 고려 사항 </li>
</ol>
<ul>
<li>데이터 타입, 데이터 값의 분포, 접근 빈도</li>
</ul>
<ol start="19">
<li>트랜잭션 모델링은?</li>
</ol>
<ul>
<li>트랜잭션을 개념적 시스템 독립적으로 정의한다.</li>
<li>트랜잭션의 입출력 기능, 형태만 정의한다.</li>
<li>검색, 갱신, 혼합(검색, 갱신)</li>
<li>개념적 설계단계에서 실행함.</li>
</ul>
<ol start="20">
<li>릴레이션의 특징</li>
</ol>
<ul>
<li>튜플의 유일성 : 모든 튜플은 서로 다른값을 갖는다</li>
<li>튜플의 무순서성 : 하나의 릴레이션에 튜플에 순서는 없다</li>
<li>속성의 원자성 : 속성값은 원자값을 갖는다</li>
<li>속성의 무순서성 : 각 속성은 릴레이션내에서 유일한 이름을 가지며, 순서는 큰 의미가 없다</li>
</ul>
<ol start="21">
<li><p>키의 종류
후보키(Candidate Key): 기본키로 사용 가능한 속성, 유일성/최소성 만족
기본키(Primary Key): 후보키 중에서 선택됨, 중복된 값과 Null값 가질 수 없음. 반드시 필요한 키
슈퍼키(Super Key): 한 릴레이션 내 속성들의 집합으로 구성된 키, 유일성○, 최소성X</p>
</li>
<li><p>데이터 모델의 구성요소</p>
</li>
</ol>
<ul>
<li>논리적구조(Structure):논리적인 개체 타입들 간의 관계, 데이터 구조 및 정적 성질을 표현</li>
<li>연산(Operation):실제 데이터를 처리하는 작업에 대한 명세로, 조작하는 기본 도구</li>
<li>제약 조건(Constraint):DB에 저장될 수 있는 실제 데이터의 논리적인 제약 조건</li>
</ul>
<ol start="23">
<li>논리 데이터 모델의 구성요소</li>
</ol>
<ul>
<li>개체</li>
<li>속성</li>
<li>관계</li>
</ul>
<ol start="24">
<li>분산 데이터베이스 시스템
목표 =&gt; 투명성!(분산투명성 고려해야함)+ 그안의 세부목표를 가짐</li>
</ol>
<ul>
<li>위치 투명성(Location Transparency)：하드웨어와 소 프트웨어의 물리적 위치를 사용자가 알 필요가 없다.</li>
<li>중복(복제) 투명성(Replication Transparency)：사용 자에게 통지할 필요없이 시스템 안에 파일들과 자원들의 부가적인 복사를 자유롭게할수 있다.</li>
<li>병행 투명성(Concurrency Transparency)：다중 사용 자들이 자원들을 자동으로 공유할 수 있다.</li>
<li>장애 투명성(Fai ure Transparency)：사용자들은 어느 위치의 시스템에 장애가 발생했는지 알 필요가 없다.</li>
</ul>
<ol start="25">
<li>기본키 속성
: 후보키 중에서 선정된 주키(MAIN KEY)</li>
</ol>
<p>-중복된 값을 가질 수 없다.
-NULL 값을 가질 수 없다.
-기본키로 검색 시 듀플을 조회할 수 있음.</p>
<ul>
<li>유일하게 특정 듀플을 유일하게 구별할 수 있는 속성</li>
</ul>
<ol start="26">
<li>Delete 명령어 설명</li>
</ol>
<ul>
<li>테이블의 행을 삭제할 때 사용한다</li>
<li>SQL을 사용 용도에 따라 분류할 경우 DML에 해당한다.</li>
<li>기본 사용 형식은 “DELETE FROM 테이블 [WHERE 조건];” 이다.</li>
<li>테이블내의 튜플들(행만)만 삭제! Drop은 테이블 자체 삭제이므로 차이가 있음.</li>
</ul>
<ol start="27">
<li>관계 해석의 논리 기호</li>
</ol>
<ul>
<li>∃: 존재한다(There exist)</li>
<li>∈: t가 r에 속함( t ∈ r )</li>
<li>∀: 모든 것에 대하여(for all)</li>
<li>∪: 합집합</li>
</ul>
<ol start="28">
<li><p>릴레이션에서 Degree(열!세로 =&gt;디열!/ 열차!) Cardinality(행!가로 =&gt; 카행!)</p>
</li>
<li><p>between은 이상이하! 를 뜻함!</p>
</li>
<li><p>분산데이터베이스 시스템(Distributed Database System)</p>
</li>
</ol>
<p>분산 데이터베이스의 구성 요소 - &#39;분산&#39;</p>
<p>1) 분산 처리기
2) 분산 데이터베이스
3) 통신 네트워크
4) 분산 트랜잭션</p>
<p>분산 데이터베이스의 구조
 : 전역, 분할(단편화), 할당, 지역 스키마</p>
<ol start="31">
<li><p>UNION: 중복제거(합집합)
UNION ALL 중복제거 x(합집합)</p>
</li>
<li><p>병행제어의 목적</p>
</li>
</ol>
<ul>
<li>여러 사용자들의 데이터베이스 공동 사용을 최대화</li>
<li>사용자의 응답 시간 최소화</li>
<li>데이터베이스 시스템의 활용도 최대화</li>
<li>데이터베이스의 일관성 유지</li>
</ul>
<ol start="33">
<li><p>데이터 베이스에서 개념들
뷰 : 하나 이상의 기본 테이블로 유도되어 만들어지는 가상 테이블
튜플 : 관계데이터 구조 테이블에서 행을 의미함
카디널리지 : 튜플의 갯수
트랜잭션 : 하나의 논리적 기능을 수행하기 위한 작업의 단위, 한꺼번에 모두 수행되어야 할 일련의 연산들</p>
</li>
<li><p>관계 대수 연산(순수 집합 연산자)</p>
</li>
<li><p>Select</p>
</li>
<li><p>Project</p>
</li>
<li><p>Join</p>
</li>
<li><p>Division</p>
</li>
</ol>
<p>그리고
일반 집합 연산자는 이게 있음 !
합집합
교집합
차집합
카티션 프로덕트</p>
<ol start="35">
<li>이상 현상
데이터 정규화가 되지 않은 테이블에서 연산을 수행(삽입, 삭제, 수정)할 시 데이터에 생기는 논리적 오류들.</li>
</ol>
<p>종류 </p>
<p>1) 삽입 이상 
자료 삽입 시 아직 정해지지 않은 부분에 대한 NULL값 등을 삽입해야 하는 경우를 뜻함
2) 갱신 이상
데이터 수정 시 중복된 다른 쪽의 데이터가 수정되지 않아 생긴 모순된 데이터 등을 지칭함
3) 삭제 이상
한 정보를 삭제했을 때 의도치 않게 해당 행의 다른 데이터까지 삭제되는 현상을 뜻함.</p>
<ol start="36">
<li>트랙잭션 기법</li>
</ol>
<ul>
<li>로킹기법 : 같은 자원을 엑세스하는 다중 트랜잭션 환경에서 DB의 일관성과 무결성을 유지하기 위해 트랜젝션의 <em>순차적 진행을 보장하는 직렬화 기법.</em></li>
</ul>
<p>타임스탬프 기법 : 트랜젝션과 트랜잭션이 읽거나 갱신한 데이터에 대해 트랜잭션이 실행을 시작하기 전에 타임스탬프를 부여하여 부여된 시간에 따라 <em>트랜젝션 작업을 수행하여 트랜잭션 간의 처리순서를 미리 정하는 기법</em></p>
<ol start="37">
<li><p>카디션 프로덕트 는 두테이블의 곱집합!  
intersect는 교집합!</p>
</li>
<li><p>수평분할 
하나의 테이블의 각 행을 다른 테이블에 분산시키는 것 
(=파티셔닝)
파티셔닝 유형 : 범위분할(rang),해시분할(hash),list분할, composite분할, 라운드로빈(round-robin)분할이 있음</p>
</li>
<li><p>시스템 카탈로그 </p>
</li>
</ol>
<ul>
<li>DBMS가 스스로 생성하고 유지함</li>
<li>저장되는 내용 메타데이터라고 함</li>
<li>시스템 자신이 필요로 하는 스키마 및 여러가지 객체에 관한 정보를 포함하고 있는 시스템 데이터베이스</li>
<li>시스템 카탈로그를 갱신하는 것은 허용 x</li>
</ul>
<p>40 차수/어트리뷰트(열)는 + 카디널리티/튜플(행)는 *  </p>
<ol start="41">
<li>속성의 특징</li>
</ol>
<ul>
<li>개체의 특성을 기술</li>
<li>데이터 베이스를 구성하는 가장 작은 논리적 단위</li>
<li>파일 구조상 데이터 항목 또는 데이터 필드에 해당됨</li>
<li>속성의 수는 디그리 임!</li>
</ul>
<ol start="42">
<li>데이터 모델링 기법</li>
</ol>
<p>1) 인덱스 정규화 : 인덱스는 키 값으로 행 데이터의 위치를 식별하는데 사용하는 기능(인덱스 정규화는 인덱스를 효과적으로 사용하려면 정규화가 되어 있어야 하는 것을 말하는 듯)</p>
<p>2) 반정규화 : 정규화된 엔티티, 속성, 관계를 시스템의 성능 향상과 개발 운영의 단순화를 위해 중복, 통합, 분리 등을 수행하는 데이터 모델링 기법</p>
<p>3) 집단화 : 속성(유형, Type)들의 세트로 구성되는 새로운 속성(유형, Type)을 정의하는데 사용되는 개념</p>
<p>4) 머징 : 둘 이상의 데이터 세트를 단일 데이터 세트로 결합 또는 공통된 컬럼명 또는 행 이름에 따라 데이터 프레임을 병합 </p>
<p>43.데이터 모델 
: 현실 세계의 정보를 컴퓨터가 이해할 수 있도록 추상화하여 표현한 모델</p>
<p>구성요소 
: 논리적 데이터 구조, 연산, 제약 조건</p>
<p>모델 절차
: 개념적 데이터 모델&gt;논리적 데이터 모델&gt;물리적 데이터 모델</p>
<ol start="44">
<li><p>차수 구하기
릴레이션에서 차수는 속성의 수!
스키마는 속성의 집합을 말함. 
스키마가 4개속성, 2개후보키 라고 했는데 왜 난 스키나 4개, 속성 2개, 후보키로 본거지.........배보..</p>
</li>
<li><p>데이터 웨어 하우스의 기본적인 OLAP
개념: 다차원으로 이루어진 데이터로부터 통계적인 요약 정보를 분석하여 의사 결정에 활용하는 방식.
roll-up, 
slicing &amp; dicing,
drill-up &amp; down, 
pivot, 
drill-through</p>
</li>
<li><p>분산데이터베이스 투명성 조건</p>
</li>
<li><p>Location Transparency (위치 투명성)
: 데이터베이스의 실제 위치를 알 필요 없이 단지 데이터베이스의 논리적 명칭만으로 액세스할 수 있음</p>
</li>
<li><p>Replication Transparency (중복 투명성; 복제 투명성)
: 동일 데이터가 여러 곳에 중복되어 있더라도 사용자는 마치 하나의 데이터만 존재하는 것처럼 사용하고, 시스템은 자동으로 여러 자료에 대한 작업을 수행</p>
</li>
<li><p>Failure Transparency (장애 투명성)
: 장애가 발생해도 트랜잭션을 정확하게 처리하고 데이터 무결성을 보장함</p>
</li>
<li><p>Concurrency Transparency (병행 투명성)
: 다수의 트랜잭션들이 동시에 실현되더라도 그 트랜잭션의 결과는 영향을 받지 않음</p>
</li>
<li><p>Division Transparency (분할 투명성)
: 하나의 논리적 릴레이션이 여러 단편으로 분할되어 각 단편의 사본이 여러 시스템에 저장되어 있음을 인식할 필요가 없음</p>
</li>
<li><p>anomaly 이상 / normalization 정규화 /  cardinality (튜플의 수)</p>
</li>
<li><p>트랜잭션 특성</p>
</li>
</ol>
<ul>
<li>원자성 : 트랜잭션 연산은 DB에 모두 반영되어 Commit(완료)되든지 아니면 반영안되어 Rollback(복구)되어야 한다.</li>
<li>일관성 : 트랜잭션이 그 실행을 성공적으로 완료하면 언제나 일관성있는 데이터베이스 상태로 변환한다.</li>
<li>독립성 : 둘 이상 트랜잭션이 동시 병행 실행될 경우 트랜잭션 실행 중 타 트랜잭션의 연산이 끼어들 수 없다.</li>
<li>지속성 : 성공적 완료된 트랜잭션 결과는 시스템이 고장나더라도 영구적으로 반영되어야 한다.</li>
<li>*
Commit과 Rollback이 나오면 원자성(Atomicity) 국룰이라고 보시면됩니다.</li>
</ul>
<ol start="49">
<li><p>함수 종속 추론 규칙
(1) 분해 규칙 : X -&gt; YZ이면 X -&gt; Y와 X -&gt; Z이다.
(3) 반사 규칙 : X -&gt; Y이면 X -&gt; Y와 X -&gt; X이다.
(4) 결합 규칙 : X -&gt; Y이고 X -&gt; Z이면 X - &gt; YZ이다.</p>
</li>
<li><p>Division 연산결과 구하기</p>
</li>
</ol>
<p>해당 조건에 대한 내용에서 그 내용을 제거한 결과값만 나타내는 것을 말함.</p>
<ol start="51">
<li>회복 기법 ?
트랜잭션 도중에 손상된 데이터베이스를 이전 상태로 복귀하는 작업</li>
</ol>
<p>트랙잭션의 연산을 수행할 때 데이터베이스를 변경하기 전에 로그 데이터를 생성하고, 
취소(Undo) 연산으로 이미 데이터베이스에 쓰여진 것도 수정할 수 있음.</p>
<ul>
<li><p>즉각 갱신 기법(Immediate Update)
트랜잭션의 연산을 수행하여 데이터를 갱신할 때 실제 데이터 베이스에 반영하는 기법
갱신한 모든 내용을 로그(Log)에 보관합니다.
회복 작업을 위해 취소(Undo)와 재시도(Redo) 모두 사용할 수 있습니다.</p>
</li>
<li><p>연기 갱신 기법(Deffered Updatae)
트랜잭션을 완료할 때까지 데이터베이스에 갱신을 연기하는 기법
트랜잭션 수행으로 갱신할 내용은 로그(Log)에 보관합니다.
트랜잭션이 부분 완료 시점에 Log의 기록을 실제 데이터 베이스에 반영합니다.
트랜잭션 수행 중에 장애가 발생하여 Rollback하여도 취소(Undo)할 필요가 없습니다.
재시도(Redo) 작업을 통해 최근의 정상적인 데이터베이스로 회복한 후에 트랜잭션을 재실행할 수 있습니다.</p>
</li>
<li><p>검사점 기법(Check Point)
트랜잭션 중간에 검사점을 로그에 보관하여 트랜잭션 전체를 취소하지 않고 검사점까지 취소할 수 있는 기법</p>
</li>
<li><p>그림자 페이지 대체 기법(Shadow Paging)-로그가 필요없음
트랜잭션의 연산으로 갱신할 필요가 있을 때 복사본인 그림자 페이지를 보관하는 기법
트랜잭션을 취소할 때 그림자 페이지를 이용하여 회복.
로그(Log), 취소(Undo), 재시도(Redo)할 필요가 없습니다.</p>
</li>
</ul>
<hr>
<p>정처기 4과목 정리</p>
<ol>
<li>문자열 처리 함수 서식과 연결</li>
</ol>
<p>함수명에 의미하는 약어가 포함되어 있음
str -&gt; string 문자
len -&gt; length 길이
cpy -&gt; copy 복사 
cmp -&gt; compare  비교
rev -&gt; reverse 변환</p>
<p>strcat - 문자열 연결 함수</p>
<ol start="2">
<li><p>c언어 계산 결과
&amp;&amp; (=and) =&gt; 모든 값이 true 인경우 1반환
||(=or) =&gt;둘중하나만 true여도 1반환
!(not) =&gt; 무조건 0이라는 값</p>
</li>
<li><p>IP프로토콜에서 사용하는 필드</p>
</li>
</ol>
<ul>
<li>Header Length :  IP 프로토콜의 헤더 길이를 32비트 워드 단위로 표시한다. </li>
<li>Packet Length :  IP 헤더를 제외한 패킷 전체의 길이를 나타내며 최대 크기는 232－1비트이다. </li>
<li>Time To Live :  송신 호스트가 패킷을 전송하기 전 네트워크에서 생존할 수 있는 시간을 지정한 것이다.  (최대값 2^16-1)</li>
<li>Version Number :  IP 프로토콜의 버전번호를 나타낸다. </li>
</ul>
<p>IP 프로토콜의 주요 특징</p>
<ul>
<li>패킷을 분할, 병합하는 기능을 수행하기도 한다. </li>
<li>비연결형 서비스를 제공한다. </li>
<li>Best Effort 원칙에 따른 전송 기능을 제공한다. </li>
<li>데이터 체크섬은 제공하지 않고, 헤더 체크섬만 제공한다.</li>
</ul>
<ol start="4">
<li><p>파이썬에서는 조건 작성시 if elif else를 씀</p>
</li>
<li><p>RIP 라우팅 프로토콜 </p>
</li>
</ol>
<ul>
<li>최단 경로 탐색에는 Bellman-Ford 알고리즘을 사용하는 거리 벡터 라우팅 프로토콜</li>
<li>라우팅 프로토콜을 IGP와 EGP로 분류했을 때 IGP에 해당한다.</li>
<li>최단경로탐색에는 Bellman-Ford 알고리즘을 사용한다.</li>
<li>최적의 경로를 산출하기 위한 정보로서 홉(거리 값)만을 고려하므로, RIP을 선택한 경로가 최적의 경로가 아닌 경우가 많이 발생할 수 있다.</li>
<li>소규모 네트워크 환경에 적합하다.</li>
<li>최대 홉 카운트를 15홉 이하로 한정하고 있다.</li>
</ul>
<ol start="6">
<li>HRN 스케줄링 방식</li>
</ol>
<ul>
<li>비선점 스케줄링</li>
<li>실행시간이 긴 프로세스에 불리한 SJF를 보완하기 위해 대기시간 및 서비스 시간을 이용</li>
<li>긴 작업과 짧은 작업 간의 지나친 불평등을 해소할 수 있다.</li>
<li>우선순위를 계산 숫자가 높은것부터 낮은순으로 순위 부여</li>
<li>(대기시간 + 서비스시간) / 서비스시간 = 우선순위값) 값이 클수록 우선순위가 높다.</li>
</ul>
<ol start="7">
<li>UNIX 운영체제</li>
</ol>
<ul>
<li>주로 서버용 컴퓨터에서 사용됨</li>
<li>time sharing system을 위해 설계된 대화식 운영체제</li>
<li>c언어로 작성되어 이식성 높고, 장치간 호환성 높다.</li>
<li>Multi user, Multi tasking 모두 지원.</li>
<li>트리 구조의 파일시스템</li>
</ul>
<ol start="8">
<li>UDP(User Datagram Protocol)프로토콜 </li>
</ol>
<ul>
<li>비연결형 및 비신뢰성 전송 서비스를 제공한다.</li>
<li>흐름 제어나 순서 제어가 없어 전송 속도가 빠르다.</li>
<li>수신된 데이터의 순서 재조정 기능을 지원하지 않는다.</li>
<li>복구 기능을 제공하지 않는다.</li>
</ul>
<ol start="9">
<li><p>파이썬의 다양한 데이터 타입
시퀀스-&gt; 리스트 - 순서있고,가변 [1,2,3]
시퀀스-&gt; 튜플   - 순서있고,불변 (1,2,3)
세트-&gt; 세트(set)   - 순서없고,중복x {1,2,3}
맵-&gt;  딕셔너리- 순서없고,key-value쌍 {&#39;a&#39;:1,&#39;b:2,&#39;c&#39;:3}</p>
</li>
<li><p>Myers가 구분한 응집도(Cohesion)
응집도
(기순교절시논우)</p>
</li>
</ol>
<ul>
<li>기능적 응집도(강함)  &gt;
순차적 응집도 &gt;
교환적 응집도 &gt;
절차적 응집도 &gt;
시간적 응집도 &gt;
논리적 응집도 &gt; 
우연적 응집도 (약함)</li>
</ul>
<ol start="11">
<li><p>데이터 결함 체크방법은 적재되어 있는 데이터를 빼고 나머지를 보면된다(적재 데이터는 이전에 체크한? 겹친 데이터로 생각하면 된다.)
LRU페이지 교체 알고리즘은? 최근까지 남아있던 것을 제거한 후 현재것을 적재시키는 것을 말함.</p>
</li>
<li><p>결함도
: 두 모듈간의 상호작용, 또는 의존도 정도를 나타내는 것</p>
</li>
</ol>
<ul>
<li><p>스탬프 결합도 : 두 모듈이 매개변수로 자료를 전달할 때, 자료구조 형태로 전달되어 이용될 때 데이터가 결합되어 있다고 한다.</p>
</li>
<li><p>내용 결합도: 하나의 모듈이 직접적으로 다른 모듈의 내용을 참조할 때 두 모듈은 내용적으로 결합되어 있다고 한다.</p>
</li>
<li><p><em>내용 참조, 자료 참조 (단어가 있으면)  내용 결합도*</em></p>
</li>
<li><p>공통 결합도 :  두 모듈이 동일한 전역 데이터를 접근한다면 공통결합 되어 있다고 한다.</p>
</li>
<li><ul>
<li>&quot;전역변수&quot; (단어가 있으면) 공통 결합도!**</li>
</ul>
</li>
</ul>
<ol start="13">
<li>모듈화(Modularity)</li>
</ol>
<ul>
<li>시스템을 모듈로 분할하면 각각의 모듈을 별개로 만들고 수정할 수 있기 때문에 좋은 구조가 된다. </li>
<li>모듈 간의 결합도가 약해야 독립적인 모듈이 될 수 있다. </li>
<li>모듈 내 구성 요소들 간의 응집도가 강해야 좋은 모듈 설계이다. </li>
<li>결합도는 모듈과 모듈 사이의 상호의존 또는 연관 정도를 의미 (음 마치 그 집단의 있는 사람들의 의존여부 )</li>
<li>응집도는 모듈이 독립적인 기능으로 정의되어 있는 정도를 의미한다.(음 마치 그 집단에 모여있는 사람들 정도?)</li>
</ul>
<p>그래서 응집도는 강하고 결합도는 약해야한다. (음 독립적으로 기능은 하지만 의존성이 높지 않아서 하나가 오류가 발생해도 큰 영향이 없게하려고 그런게 아닐까?)</p>
<ol start="14">
<li><p>IP주소 체계 
1) IPv4
ㄱ. 32비트 주소
ㄴ. 유니캐스트/멀티캐스트/브로드캐스트 사용
ㄷ. 헤더가 가변적임
2) IPv6
ㄱ. 128비트 주소
ㄴ. 기존 IPv4의 주소 부족 문제를 해결하기 개발
ㄷ. 인증성/기밀성/무결성 지원 (=보안성 강화)
ㄹ. 유니캐스트, 애니캐스트, 멀티캐스트 사용
ㅁ. 헤더가 40바이트(320비트)로 고정되어 있음  패킷헤더도 아님!
ㅂ. 16비트씩 8부분의 16진수로 표시한다.
ㅅ. 등급별, 서비스별로 패킷을 구분할 수 있어서 품질보장이 용이함
ㅇ. 확장기능을 통해 보안기능을 제공한다.</p>
</li>
<li><p>C언어로 계산법 (어려워죽어..)
예로 arr[2][3] ={1,2,3,4,5,6}
여기서 arr[2][3]의 2는 세로  3은 가로를 뜻한다 
즉 행2,열3 을 뜻함
123
456 이라고 생각하면 된다. 그렇게 보고 문제를 풀면 좀 쉬울 듯
첫번째!
*(p[0]+1) + *(p[1]+2)는 p[0][1]  와 p[1][2] 를 더한 값을 보면 된다.
위 
123
456에서 해당부분을 찾는다면 
2,6인 것을 알 수 있다.  합은 8임.</p>
</li>
</ol>
<p>두번째,  <em>(</em>(p+1)+0 )+<em>(</em>(p+1)+1)에서 p+1은 p[1]을 뜻하고 뒤 +0은 p[0]을 뜻한다. 그래서 앞부분이 뜻하는건 p[1][0]뒷 내용도 마찬가지로 보면 p[1][1]으로 보면된다.
그래서 4와 5를 뜻하고 합은 9인것을 알 수 있다.
그래서 정답은 8,9! 
쉽죠잉?</p>
<ol start="16">
<li>자바에서 예외란?</li>
</ol>
<ul>
<li>오동작이나 결과에 악영향을 미칠 수 있는 실행 시간 동안에 발생한 오류</li>
<li>배열의 인덱스가 그 범위를 넘어서는 경우 발생하는 오류</li>
<li>존재하지 않는 파일을 읽으려고 하는 경우에 발생하는 오류 
문법오류는 컴파일 시 에러가 발생하고 때문에 프로그램 실행이 불가능하여 이건 예외로 보지 않음!</li>
</ul>
<ol start="17">
<li>IP 프로토콜</li>
</ol>
<ul>
<li>ARP(Address Resolution Protocol) : IP 네트워크 상에서 IP주소를 MAC주소로 변환하는 프로토콜(물리적 주소로 바꾸는 역할을 함)</li>
<li>PPP(Point-to-Point Protocol) : 점대점 데이터링크를 통해 3계층 프로토콜들을 캡슐화시켜 전송하는 프로토콜</li>
<li>ICMP(Internet Control Message Protocol) : IP와 조합하여 통신 중에 발생하는 오류의 처리와 전송 경로 변경 등을 위한 제어 메시지를 관리하는 역할을 하는 프로토콜</li>
</ul>
<ol start="18">
<li>Best Fit
: 내부 단편화(자투리)가 가장 적게 남는 공간에 넣음
여기서 제안하는 프로그램 크기를 모든 기억 공간 크기에 넣고 값을 빼서 가장 적게 나오는 것으로 고르면 된다.!  즉, 문제에서 Best Fit을 물을 시 내부단편화가 제일 작은 보기를 찾으면 됨!</li>
</ol>
<p>여기서 예시가 17KB프로그램 적재시라고 했고 빈기억공간 크기는 20KB, 16KB, 8KB, 40KB  이라고 했는데 가장 적은건 3KB이다 (20KB일때) ! 그리고 -로 떨어지는 건 불가한것!</p>
<p>그외<br>First Fit: 들어갈 수 있는 첫 번째 공간에 넣음(여기서는 20KB이겟지? 이건 맞는지 모르겠네)
 Worst Fit: 가장 큰 공간에 넣음(여기서는 23KB)
으로 알면된다.</p>
<ol start="19">
<li>1, 2, 1, 0, 4, 1, 3 일 경우 FIFO 알고리즘에 의한 페이지 교체의 경우 프레임의 최종 상태는?</li>
</ol>
<p>12
1//
120 
204
041
413</p>
<p>기출 22.3.05 75번  3개의 페이지 프레임을 갖는 시스템에서 페이지 참조 순서가 1, 2, 1, 0, 4, 1, 3 일 경우 FIFO 알고리즘에 의한 페이지 교체의 경우 프레임의 최종 상태는? 
이거 무슨말인지 모르겠네... 
찾아보자..</p>
<ol start="20">
<li>UNIX 시스템의 쉘(shell)의 주요 기능</li>
</ol>
<ul>
<li>사용자 명령을 해석하고 커널로 전달하는 기능을 제공한다.</li>
<li>반복적인 명령 프로그램을 만드는 프로그래밍 기능을 제공한다.</li>
<li>초기화 파일을 이용해 사용자 환경을 설정하는 기능을 제공한다.</li>
</ul>
<p>커널은 메모리나 프로세스 관리 ! 쉘은 명령 해석해서 커널로 전달만 ! 기능을 제공하는 부분이 쉘 그 기능을 바탕으로 무언가를 하는 건 커널!~**</p>
<p>21.OSI 7계층
1계층 - 물리계층(Physical Layer) : Coax, Fiber, Wireless
2계층 - 데이터 링크계층(DataLink Layer) : Ethernet, SLIP, PPP, FDDI, HDLC
3계층 - 네트워크 계층(Network Layer) : IP, IPSec, ICMP, IGMP
4계층 - 전송 계층(Transport Layer) : TCP, UDP, ECN, SCTP, DCCP
5계층 - 세션 계층(Session Layer) : VARIOUS API;S, SOCKETS
6계층 - 표현 계층(Presentation Layer) : SSL, FTP, IMAP, SSH
7계층 - 응용 계층(Application Layer) : HTTP, FTP, IRC, SSH, DNS</p>
<ol start="22">
<li>상호 배제 기법</li>
<li>데커의 알고리즘Dekker Algorithm</li>
</ol>
<ul>
<li>프로세스가 두개일때 상호 배제를 보장하는 최초의 알고리즘</li>
<li>flag와 turn 변수를 사용하여 조정</li>
<li><em>상호배제보장/.최초*</em></li>
</ul>
<ol start="2">
<li>램퍼드 알고리즘   Lamport Algorithm </li>
</ol>
<ul>
<li>프로세스 n개의 상호 배제 문제를 해결한 알고리즘</li>
<li>프로세스에게 고유한 번호를 부여하고, 번호를 기준으로 우선순위를 정하여 우선순위가 높은 프로세스가 먼저 임계구역에 진입하도록 구현.</li>
<li><em>우선순위/고유번호부여*</em></li>
</ul>
<ol start="3">
<li>피터슨 알고리즘  피터슨 알고리즘 </li>
</ol>
<ul>
<li>프로세스가 두개일때 상호 배제를 보장, 데커의 알고리즘과 유사하지만 상대방에게 진입 기회를 양보한다는 차이가 있고 보다 더 간단하게 구현됨</li>
<li><em>상호배제보장 인데 진입기회양보 데커보다 간단</em></li>
</ul>
<ol start="4">
<li>세마포어 Semaphore</li>
</ol>
<ul>
<li>공유된 자원의 데이터 혹은 임계영역 등에 따라 여러 Process 혹은 Thread가 접근하는 것을 막아줌(동기화 대상이 하나 이상)</li>
<li><ul>
<li>임계영역**</li>
</ul>
</li>
</ul>
<ol start="23">
<li>모듈의 특징</li>
</ol>
<ul>
<li>독립적인 기능을 가진 단위</li>
<li>유일한 이름을 가져야 함</li>
<li>독립적 컴파일 가능하게함.</li>
<li>다른모듈에서도 접근이 가능하게 폐쇄적이지만 접근 불가능은 x</li>
</ul>
<ol start="24">
<li>응집도 종류</li>
</ol>
<ul>
<li>Temporal Cohension(시간적 응집도) : 모듈 내 구성 요소들이 서로 다른 기능을 같은 시간대에 함께 실행하는 경우의 응집도</li>
<li>Logical Cohension(논리적 응집도): 모듈 내 구성 요소들이 같은 범주에 속하는 기능끼리 묶인 경우(ex. 새글, 불러오기, 저장하기, 다른이름으로 저장하기)</li>
<li>Coincidental Cohension(우연적 응집도): 모듈 내 구성 요소들이 뚜렷한 관계없이 묶인 경우</li>
<li>Sequential Cohension(순차적 응집도): 모듈 내 구성 요소들이 이전의 명령어로부터 나온 출력결과를 그 다음 명령어의 입력자료로 사용하는 경우(ex. 총점과 평균의 관계)</li>
</ul>
<ol start="25">
<li>자바에서 연산자 우선순위</li>
</ol>
<p>-- &gt; % &gt; &amp; &gt; =</p>
<ol start="26">
<li><p>SSTF (shortest seek time first ) 스케쥴링 사용한 처리 순서
=&gt; 현재 헤드위치에서 가장 가까운 것 부터
예 : 98, 183, 37, 122, 14, 124, 65, 67 / 53현재 헤드
53이 시작이니 가장 가까운것 65
두번째 , 가장 이동 거리 짧은 것 =&gt; 현재 트랙과 남아있는 트랙 중 차이가 적은 것 
53 - 65 - 67 - 37 - 14 - 98 - 122 - 124 - 183</p>
</li>
<li><p>IPaddress
A class에 속하는 ip 주소 범위: 0.0.0.0 ~ 127.255.255.255
B class에 속하는 ip 주소 범위: 128.0.0.0 ~ 191.255.255.255
C class에 속하는 ip 주소 범위: 192.0.0.0 ~ 223.255.255.255</p>
</li>
</ol>
<p>a는 127까지
b는 128-191까지
c는 192-223까지 
d는 224-239까지 
e 255까지</p>
<ol start="28">
<li>모듈의 독립성을 높이기 위한 결합도와 관련된 설명</li>
</ol>
<ul>
<li>오류가 발생했을 때 전파되어 다른 오류의 원인이 되는 파문 효과(Ripple Effect)를 최소화해야 한다.</li>
<li>인터페이스가 정확히 설정되어 있지 않을 경우 불필요한 인터페이스가 나타나 모듈 사이의 의존도는 높아지고 결합도가 증가한다.</li>
<li>다른 모듈과 데이터 교류가 필요한 경우 전역변수(Global Variable)보다는 매개변수(Parameter)를 사용하는 것이 결합도를 낮추는 데 도움이 된다.</li>
<li>모듈이 변수를 공유해 사용하게 하거나 제어 정보를 고류하게 하면 모듈간의 결합도가 높아지기에 이를 줄여야한다.</li>
</ul>
<ol start="29">
<li>TCP 헤더와 관련된 설명 
원도우 크기는 16비트로 65535바이트임. </li>
</ol>
<p>-순서번호(시퀀스넘버)는 전달하는 바이트마다 번호가 부여됨</p>
<ul>
<li>수신번호확인(Acknowledgement Number)은 상대편 호스트에서 받으려는 바이트의 번호를 정의한다</li>
<li>체크섬(Checksum)은 데이터를 포함한 세그먼트의 오류를 검사한다.
30 페이지 교체 (page Replacement)의 알고리즘</li>
</ul>
<p>OPT - Optimal : 앞으로 가장 오랫동안 사용되지 않을 페이지 교체
FIFO - First In First Out
LRU - Least Recently Used : 가장 오랫동안 사용되지 않은 페이지 교체
LFU - Least Frequently Used : 참조 횟수가 가장 적은 페이지 교체
MFU - Most Frequently used : 참조 횟수가 가장 많은 페이지 교체
NUR - Not Used Recently : 최근에 사용하지 않은 페이지 교체</p>
<ol start="31">
<li><p>C언어에서의 변수 선언
else 는 예약어라 변수명으로 사용할 수 없고 첫자리가 숫자거나 예약어는 사용이 불가능하다. 
언더바나 영문 대소문자는 모두 사용 가능!</p>
</li>
<li><p>자동요청 방식(ARQ: Automatic Repeat reQuest)</p>
</li>
</ol>
<ul>
<li>Stop-and-Wait ARQ(정지-대기 ARQ): 송신 측이 하나의 블록을 전송한 후 수신 측에서 에러의 발생을 점검한 다음, 에러 발생 유무 신호를 보내올 때까지 기다리는 방식</li>
<li>Go-Back-N ARQ: 여러 블록을 연속적으로 전송하고, 수신 측에서 부정 응답(NAK)을 보내오면 송신 측이 오류가 발생한 블록부터 모두 재 전송</li>
<li>Selective-Repeat ARQ(선택적 재전송 ARQ): 여러 블록을 연속적으로 전송하고, 수신측에서 부정 응답(NAK)을 보내오면 송신 측이 오류가 발생한 블록만을 재전송</li>
<li>Adaptive ARQ(적응적 ARQ): 전송 효율을 최대로 하기 위해서 데이터 블록의 길이를 채널의 상태에 따라 동적으로 변경하는 방식</li>
</ul>
<ol start="33">
<li>192.168.1.0/24 네트워크를 FLSM 방식을 이용하여 4개의 Subnet으로 나누고 IP Subnet-zero를 적용했다. 이 때 Subnetting 된 네트워크 중 4번째 네트워크의 4번째 사용가능한 IP는 무엇인가? </li>
</ol>
<p>192.168.1.(00)000000 (0)
192.168.1.(01)000000 (64)
192.168.1.(10)000000 (128)
192.168.1.(11)000000 (192)</p>
<p>여기서 4번째 이니 192.168.1.196임.</p>
<p>뭐라는걸까...........개어렵ㄷr ... 와로알왈왈</p>
<ol start="34">
<li>프로세스</li>
</ol>
<ul>
<li>프로세스 준비과정에서 실행으로 바뀌는것 디스패치!</li>
<li>프로세시 제어 블록은 식별자, 상태, 실시간 통계, 스레드, 주소공간 자원, 스택 등  등의 정보로 구성됨.(음 맞나)</li>
<li>상태 레지스터 내용을 보관하고 다른 레지스터를 적재하는 과정을 문맥교환이라고 함.(콘텍트 스위칭)</li>
<li>프로세스의 실행단위를 스레드라고 함.</li>
</ul>
<ol start="35">
<li>충돌 발생에 관련된 제어방식</li>
</ol>
<ul>
<li>Collision Domain(충돌도메인) =&gt; 충돌 발생을 검출 
: 충돌 발생을 검출할 수 있는 브리지 간 혹은 다른 계층 장치 간의 이더넷 세그먼트 범위</li>
<li>CSMA/CD (Carrier-sense multiple access with collision detection) &quot;충돌 감지&quot; =&gt; 규칙있게 접근하기 위한 제어 방식
: 이더넷에서 각 단말이 전송 공유 매체에 규칙있게 접근하기 위한 매체 엑세스 제어 방식</li>
<li>CSMA/CA(Carrier-sense multiple access with collision avoidance) 
: 충돌 방지 =&gt; 충돌을 회피하기 위해서 대비하는 것 
무선 랜에서 데이터 전공 시, 매체가 비어있음을 확인한 후 충돌을 회피하기 위해 임의 시간을 기다린 후 데이터를 전송하는 방식.</li>
</ul>
<ol start="36">
<li>교착상태 해결 방법</li>
</ol>
<ul>
<li>Detection(탐지)
: 교착상태 발생을 허용하고 발생 시 원인을 규명하여 해결 (ex 자원할당 그래프)</li>
<li>Avoidance (회피)
: 교착상태 가능성을 배제하지 않고 적절하게 피해나가는 방법 (ex 은행원 알고리즘)</li>
<li>Recovery (복구)
: 교착상태 발견 후 현황대기를 배제시키거나 자원을 중단하는 메모리 할당 기법 (ex 선점, 프로세스 중지(희생자 선택)</li>
<li>Prevention(예방)
: 교착상태의 필요조건을 부정함으로써 교착상태가 발생하지 않도록 미리 예방하는 방법 (ex 환형대기, 비선점, 점유와 대기, 상호배제 4가지 부정) </li>
</ul>
<ol start="37">
<li><p>결합도 외우기(높은순)
내게 공부를 하라고 하지말아요
제가 스트레스 받자나요
내용 공통 외부 제어 스탬프 자료</p>
</li>
</ol>
<p>응집도 외우기
높은-&gt; 낮은
기순교절시절우
우리 논산 시절 기억나 교자랑 순대 기대했었는데
낮은 -&gt; 높은
우 논 시 절 교 순 기</p>
<p>기순 교절 시논우 </p>
<hr>
<p>정처기 5과목 정리</p>
<ol>
<li>소프트웨어 개발 정보보안 3요소 (무기가)
무결성,기밀성,가용성 </li>
</ol>
<p>-무결성 : 인가된 사용자에 대해서만 자원 수정이 가능하며 전송중인 정보는 수정되지 않는다. 
-기밀성 : 인가된 사용자에 대해서만 자원 접근이 가능하다. 
-가용성 : 인가된 사용자는 가지고 있는 권한 범위 내에서 언제든 자원 접근이 가능하다. </p>
<ol start="2">
<li><p>tcp wrapper
어떤 외부 컴퓨터가 접속되면 접속 인가 여부를 점검해서 인가된 경우에는 접속이 허용되고, 그 반대의 경우에는 거부할 수 있는 접근제어 유틸리티</p>
</li>
<li><p>Zing
기기를 키오스크에 갖다 대면 원하는 데이터를 바로 가져올 수 있는 기술로 10㎝ 이내 근접 거리에서 기가급 속도로 데이터 전송이 가능한 초고속 근접무선통신(NFC : Near Field Communication) 기술</p>
</li>
</ol>
<p>그 외 다양한 기술들</p>
<ul>
<li><p>BcN(Broadband Convergence Network) : 음성·데이터·유무선 등 통신·방송·인터넷이 융합된 품질 보장형 광대역 멀티미디어 서비스를 공간에 제한없이 실시간으로 이용할 수 있는 차세대 네트워크 환경</p>
</li>
<li><p>Marine Navi는 소형 선박에 설치된 GPS 기반 선박자동 식별장치(AIS: Automatic Identification System)를 기본으로 주변 선박의 이동 속도와 위치를 파악</p>
</li>
<li><p>엘티이(LTE), 5G와 같은 셀룰러 이동통신망을 통해 차량이 다른 차량이나 교통 인프라, 보행자, 네트워크 등과 정보를 서로 주고받는 차량 통신 기술.</p>
</li>
</ul>
<ol start="4">
<li>응용프로그램 취약점 관리
패치 관리 : 응용프로그램에 대한 패치 또는 서비스 팩 적용</li>
</ol>
<ul>
<li>응용프로그램 실행권한의 제한 필요</li>
<li>운영체제의 접근 제한</li>
<li>정보 수집 제한</li>
<li>불필요한 서비스 및 악성 프로그램의 확인 및 제거</li>
<li>시스템 무결성 검사 : 주요 파일을 검사하여 변경 내역 확인</li>
</ul>
<p>취약점 분석 </p>
<ul>
<li>환경 및 시설: 도난, 정전-오작동, 천재지변</li>
<li>하드웨어: 고장-오작동, 데이터 유실</li>
<li>소프트웨어: 소프트웨어 장애, 정보유출, 데이터 소실</li>
</ul>
<ol start="5">
<li>소프트웨어 개발 프레임워크 </li>
</ol>
<ul>
<li>반제품 상태의 제품을 토대로 도메인별로 필요한 서비스 컴포넌트를 사용하여 재사용성 확대와 성능을 보장 받을 수 있게 하는 개발 소프트웨어이다. </li>
<li>설계 관점에 개발 방식을 패턴화시키기 위한 노력의 결과물인 소프트웨어 디자인 패턴을 반제품 소프트웨어 상태로 집적화시킨 것으로 볼 수 있다. </li>
<li>프레임워크의 동작 원리를 그 제어 흐름의 일반적인 프로그램 흐름과 반대로 동작한다고 해서 IoC(Inversion of Control)이라고 설명하기도 한다. </li>
</ul>
<ol start="6">
<li>클라우드 기반 HSM(Cloud-based Hardware Security Module)</li>
</ol>
<ul>
<li>클라우드(데이터센터) 기반 암호화 키 생성, 처리, 저장 등을 하는 보안 기기이다.</li>
<li>국내에서는 공인인증제의 폐지와 전자서명법 개정을 추진하면서 클라우드 HSM 용어가 자주 등장하였다.</li>
<li>클라우드에 인증서를 저장하므로 기존 HSM 기기나 휴대폰에 인증서를 저장해 다닐 필요가 없다.</li>
<li>하드웨어적으로 구현되어 소프트웨어식 암호 기술에 내재된 보안 취약점 해결 가능</li>
</ul>
<ol start="7">
<li>Mesh Network (그물#)</li>
</ol>
<ul>
<li>직접 접속되는 그물 모양의 네트워크</li>
<li>통신량이 많은 곳에서 구성될 경우 경제적, 간편함. 하지만 다수 회선이 세분화 되어 있어 비경제적일 수도 ...</li>
<li>대용량을 빠르고 안전하게 전달할 수 있어 군, 행사장에서 주로 사용</li>
</ul>
<ol start="8">
<li>물리적 위협</li>
</ol>
<ul>
<li>천재지변, 방화나 테러로 인한 하드웨어와 기록장치를 물리적으로 파괴하는 것, 하드웨어의 파손과 고장으로 인한 장애</li>
</ul>
<ol start="9">
<li>악성코드의 유형</li>
</ol>
<ul>
<li>Worm : 악성코드의 유형 중 다른 컴퓨터의 취약점을 이용하여 스스로 전파하거나 메일로 전파되며 스스로를 증식하는 것 
(취약점 이용해 전파하며 스스로 증식)</li>
<li>Rogue Ware(Rogue security software; 가짜 백신 소프트웨어) : 사용자가 컴퓨터에 바이러스가 있다고 잘못 믿게 하고 컴퓨터에 실제로 악성 프로그램을 설치토록 하거나, 가짜 악성 프로그램 제거 도구에 대한 비용을 지불하도록 설득함. 공포심을 통해 사용자를 조종
(바이러스가 있다고 하는 등 공포심을 통해 사용자 조종)</li>
<li>Adware : 특정 소프트웨어를 실행할 때 또는 자동으로 활성화되는 광고프로그램으로 이 자체는 악성코드로 보기는 힘들지만, 무분별한 광고 팝업을 뜨게 하는 등의 악용 위험성으로 악성코드로 분류되기도 함.
( 자동으로 활성화되는 광고프로그램)</li>
<li>Reflection Attack(반사공격) : 송신자가 생성한 메시지를 가로챈 공격자가 그 메시지를 다시 송신자에게 재전송하여 접근 권한을 얻는 형태의 공격 방법. 
(음 스팸인건가..? 메서지를 다시보내며 접근권환 얻으며 공격)</li>
</ul>
<ol start="10">
<li>DoS(Denial of Service) 공격 </li>
</ol>
<ul>
<li>Ping of Death : 허용범위 이상의 ICMP패킷을 전송해 대상 시스템의 네트워크 마비시키는 것 (ICMP가 패킷을 많이 쏘니 핑하고 죽어삣네. 핑오브데스)</li>
</ul>
<p>-Session Hijacking(세션 가로채기) : 컴퓨터 시스템의 정보나 서비스에 무단으로 접근하기 위해 유효한 컴퓨터 세션(세션 키라고도 함)을 이용하는 것 일반적인 예로 두 컴퓨터 간에 활성화된 상태(즉, 로그인된 상태)에서 공격자가 피공격자의 로그인 정보를 활용하여 자신에게 필요한 행위를 하는 것을 뜻한다. 
(유효한 세션을 이용해 정보를 활용해 필요행위를 하는 것 == 원격제어인가?)</p>
<ul>
<li><p>Piggyback Attack(피그백 공격) : 공격자가 다른 사용자의 연결에서 계정을 사용하지 않는 비활성 기간(비활성 간격)을 이용하여 시스템에 액세스(접근)한다. 이는 간선(회선 간) 공격이라고도 불린다.</p>
</li>
<li><blockquote>
<p>쉽게 설명하자면, 시스템에 대한 합법적인 권한을 가진 사용자가 시스템에 접근할 때, 활성화된 기간(직접 로그인 인증을 받아야 하는 상황)에는 접근 권한이 없는 공격자가 비활성화된 기간(합법적 사용자가 시스템에 접근 인증을 받은 상황)에 마치 사용자와 관련있는 사람인 듯이 태그를 붙여 몰래 뒤따라 들어가는 것이라 할 수 있다.
(비활성 기간을 이용해 접근해 공격)</p>
</blockquote>
</li>
<li><p>XSS (크로스 사이트 스크립팅) : 웹사이트에 악성 스크립트를 주입하는 행위. 공격자가 상대방의 브라우저에 스크립트가 실행되도록 해 사용자의 세션을 가로채거나, 웹사이트를 변조하거나, 악의적 콘텐츠를 삽입하거나, 피싱 공격을 진행하는 것. 
(악성스크립트 주입 , 바이러스 까는건가..?)</p>
</li>
<li><p>Smurf 공격 : 브로드 캐스트를 활용하여 공격 대상이 네트워크의 임의의 시스템에 패킷을 보내게 만드는 공격</p>
</li>
<li><p>SYN Flooding : 존재하지 않는 클라이언트가 서버별로 한정된 접속 가능 공간에 접속한 것처럼 속여 다른 사용자가 서비스를 이용하지 못하게 하는 것</p>
<p>-Land : 패킷 전송 시 출발지 IP주소와 목적지 IP주소 값을 똑같이 만들어서 공격 대상에게 보내는 공격 방법</p>
</li>
</ul>
<p>11.소프트웨어 개발 프레임 워크 
: 개발해야할 애플리케이션의 일부분이 이미 내장된 클래스 라이브러리로 구현이 되어 있는 것 </p>
<ol start="12">
<li><p>대칭 암호화와 비대칭 암호화
대칭 암호화 : 비교적 실행 속도가 빠름, 다양한 암호의 핵심함수로 사용될 수 있음, 대칭 암호화 알고리즘은 키교환이 필요해 교환 시 키 탈취 문제가 발생할 수 있음, 대표적 대칭키 암호 알고리즘은 AES,IDEA등이 있음(난 에이스,이디야로 보여서 그렇게 외워야짐...)
비대칭 암호화 : 자신만이 보관하는 비밀키를 이용해 인증, 전자서명 등 적용 가능</p>
</li>
<li><p>비용 산정 계산법
노력 측정 = 개발기간 X 투입인원
개발비용 측정 = 개발기간 X 투입인원 x 단위비용
개발기간 측정 = 예측된 LOC(라인) / (투입인원 X 1인당 월평균 LOC)
생산성 측정 = 개발된 LOC / (투입인원 X 개발기간)</p>
</li>
<li><p>역할 기반 접근통제  (Role Based Access Control)
: 권한이 있는 사용자들만 접근할 수 있는 보안 방법 </p>
</li>
</ol>
<p>MAC (Mandatory Access Control)</p>
<ul>
<li>강제 접근 통제</li>
<li>미리 정해진 자원의 보안 레벨과 사용자에게 허락된 접근 권한 비교 </li>
</ul>
<p>DAC (Discretionary Access Control)</p>
<ul>
<li>임의적 접근통제</li>
<li>자원에 대한 접근을 사용자나 그룹의 신분에 따라 제한</li>
<li>자원의 소유권을 가진 사람이 다른 사람의 접근을 허용하거나 제한할 수 있음 </li>
</ul>
<p>RBAC (Role Based Access Control)</p>
<ul>
<li>사용자 역할에 따른 접근 통제</li>
<li>개별적인 신분이 아니라 조직 내 그룹 / 역할에 따라 부여</li>
</ul>
<ol start="15">
<li>COCOMO(Constructive Cost Model) 모형</li>
</ol>
<ul>
<li>보엠이 고안한 </li>
<li>원시 프로그램 규모(LOC)에 의한 용 산정 방법.</li>
<li>man-month = 투입 노력
[개발 유형에 따른 3종류]
organic(조직형)</li>
<li>5만 라인 이하</li>
<li>사무 처리용, 업무용, 과학용 소프트웨어 개발에 적합
semidetached(반분리형)</li>
<li>30만 라인 이하</li>
<li>컴파일러, 인터프리터 개발에 적합
embedded (내장형)</li>
<li>30만 라인 이상</li>
<li>미사일 유도 시스템, 실시간 처리 시스템 개발에 적합</li>
</ul>
<ol start="16">
<li><p>사용자 인증 유형 
1) 지식 - 본인이 알고 있는 것 (ex. 패스워드, PIN 등)
2)  소유 - 본인이 가지고 있는 것 (ex. 토큰, 스마트카드 등)
3) 존재 - 본인을 나타내는 것 (ex. 홍채, 지문 등)
4) 행위 - 본인이 하는 것 (ex. 서명, 움직임, 음성 등)</p>
</li>
<li><p>사용자가 로그인하여 명령을 내리는 과정에 대한 시스템의 동작 
:Authentication (인가!)</p>
</li>
</ol>
<ol start="18">
<li>IT 기술?</li>
</ol>
<ul>
<li><p>SDN(Software Defined Networking) : 네트워크를 제어부, 데이터 전달부로 분리하여 네트워크 관리자가 보다 효율적으로 네트워크를 제어, 관리할 수 있는 기능. 안정성, 속도, 보안 등 소프트웨어로 제어, 관리하기 위해 개발됨. 경로 수정을 통해 인터넷상 발생 문제를 처리할 수 있음.</p>
</li>
<li><p>NFS(Network File System) : 네트워크상에서 공유되는 파일시스템. 다른 원격 호스트의 파일 시스템을 로컬 디스크에 접근하듯 간단하게 접근하여 자신의 디렉토리처럼 사용할 수 있다</p>
</li>
<li><p>Network Mapper : 네트워크 보안을 위한 유틸리티. 네트워크의 보안을 위해 물리적 연결과 어떤 서버와 운영 체제가 작동 중인지 따위를 조사하는 응용 프로그램</p>
</li>
<li><p>AOE Network(Activity On Edge Network) : 어떤 프로젝트를 마치기까지 수행되는 작업의 각 단계(상태)를 그래프의 정점(Vertex)으로 표현하고, 작업 하나가 완료되어 다음 단계로 넘어가는 시간을 그래프의 간선(Edge)으로 나타낸 방향 그래프 </p>
</li>
</ul>
<ol start="19">
<li>프로젝트 일정 관리시 사용하는 차트</li>
</ol>
<p>PERT 차트</p>
<ul>
<li>네트워크 도표 작성</li>
<li>작업들 간의 상호 관련성, 결정경로, 경계시간, 자원할당 등을 제시한다. </li>
</ul>
<p>GANTT 차트</p>
<ul>
<li>막대도표를 이용해 표시</li>
<li>시간선 차트</li>
<li>수평 막대의 길이는 각 작업의 기간을 나타냄 (소작업별로 작업기간을 한눈에 볼수 있고 자원 배치 계획에 유용하게 사용됨.)</li>
<li>CPM네트워크로 부터 만드는 것 가능함. </li>
</ul>
<ol start="20">
<li>정보 시스템 
고가용성 솔루션(HACMP:High Availability Cluster Multi Processing)</li>
</ol>
<ul>
<li>AIX를 기반으로 한 IBM의 High Availability Solution</li>
<li>Resource의 중복 또는 공유를 통해 Application의 보호를 가능하게 해줌</li>
<li>같은 Data를 공유하거나 동시에 access하는 node들에서 여러 개의 application을 실행하게 해줌</li>
<li>두대 이상의 시스템을 하나의 Cluster로 묶어 Cluster내의 한 시스템에서 장애가 발생할 경우 다른 시스템이 장애가 발생한 시스템의 자원을 인수할 수 있도록 하여 서비스의 중단을 최소화 할 수 있도록 도와주는 솔루션
(다수의 프로그램을 동시에 연결)</li>
</ul>
<p>점대점 연결 방식(Point-to-Point Mode)</p>
<ul>
<li>네트워크에 있어 물리적으로는 중개 장치를 통과하지 않고 한 지점에서 다른 지점으로 직접 가는 채널</li>
<li>두 스테이션간을 별도의 회선을 사용하여 1 대 1로 연결.</li>
<li>전용회선이나 공중 전화 회선을 이용.</li>
<li>회선 구성이 간단하고 대용량 전송에 유리.</li>
<li>별도의 회선과 포트에 따른 높은 설치비용
(중개장치없이 한지점에서 다른지점으로 직접 갈 수 있음)</li>
</ul>
<p>스턱스넷(Stuxnet)</p>
<ul>
<li>2010년 6월에 발견된 웜 바이러스</li>
<li>윈도우를 통해 감염, 지맨스산업의 SW 및 장비를 공격</li>
</ul>
<p>루팅(Rooting)</p>
<ul>
<li>모바일 기기에서 구동되는 안드로이드 운영체제상에서 최상위 권한 (루트 권한)을 얻음으로 해당 기기의 생산자 또는 판매자 측에서 걸어 놓은 제약을 해제하는 행위</li>
</ul>
<ol start="21">
<li>용어찾기 ! 제목을 뭐라짓지</li>
</ol>
<ul>
<li>Parsing
: 하나의 프로그램을 런타임 환경(예를 들면, 브라우저 내 자바스크립트 엔진)이 실제로 실행할 수 있는 내부 포맷으로 분석하고 변환하는 것을 의미함</li>
<li>LAN Tapping
:  처음 들어보는 용어이고, 찾아도 제대로된 정의가 나오지 않으나 Lan+Tapping으로 해석한다면 LAN신호를 직접 자신에게 끌어오는 방식의 공격정도로 해석 가능함</li>
<li>Switch Jamming
: 스위치의 기능이 방해 받아 정상 동작을 하지 못해 스위치가 더미 허브처럼 작동 하게 되는 것 (MAC주소를 흘려보내 더미허브처럼 자도하는 것)</li>
<li><blockquote>
<p>Switch + Jamming(방해)</p>
</blockquote>
</li>
<li>FTP(SYN) Flooding
: TCP의 3 Way Handshake 취약점을 이용한 DoS 공격으로 다량의 SYN패킷을 보내 백로그큐를 가득 채우는 공격 (취약점을 이용한 디도스 공격!)
: 통상적으로 위의 공격법을 TCP SYN Flooding 이라고 칭하는 경우가 많음
: FTP프로토콜을 사용한 서버에 다량의 SYN 패킷을 보내 마비시키는것을 FTP Flooding이라고 볼 수 있음. </li>
</ul>
<ol start="22">
<li>스토리지 시스템</li>
</ol>
<ul>
<li>DAS : 직접 연결 저장장치 -&gt; 데이터 저장장치를 호스트버스 어댑터에 직접연결하는 방식!</li>
<li>NAS : 네트워크 결합 스토리지</li>
<li>NFC : 근거리 무선 통신</li>
</ul>
<ol start="23">
<li>블루투스 공격</li>
</ol>
<ul>
<li>블루버그: 블루투스 장비사이의 취약한 연결 관리를 악용한 공격</li>
<li>블루스나프(블루스나핑): 블루투스의 취약점을 활용하여 장비의 파일에 접근하는 공격으로 OPP를 사용하여 정보를 열람</li>
<li>블루재킹: 블루투스를 이용해 스팸처럼 명함을 익명으로 퍼뜨리는 것</li>
<li>블루프린팅(BluePrinting) - 블루투스 공격 장치의 검색 활동을 의미</li>
</ul>
<ol start="24">
<li><p>시스템 종류?
Honeypot : 비정상적 접근의 탐지를 위해 의도적으로 설치해 둔 시스템, 침입자를 속여 실제 공격처럼 보여주며 크래커를 추적 및 공격기법의 정보를 수집하는 역할을 함.
Apache : 월드 와이드 웹 컨소시엄(W3C)에서 사용하고 아파치 소프트웨어 재단에서 관리 및 운영하는 서버용 오픈소스 소프트웨어(아파치!!)
Hadoop : 오픈 소스를 기반으로 한 분산 컴퓨팅 플랫폼 
MapReduce : 대용량 데이터를 분산 처리하기 위한 목적으로 Google에 의해 고안된 프로그래밍 모델</p>
</li>
<li><p>파이썬 기반의 웹크롤링 프레임 워크 = Scrapy (가볍고 확장성 좋음)</p>
</li>
</ol>
<p>그외
Li-fi : 스펙트럼의 빛을 이용한 5세대 이동 통신 기술
SBAS(위성항법보강시스템) : GPS의 오차를 보정해 신뢰성과 안정성을 높인 기법
CrawlCat  : 구글에서 개발한 웹 크롤링 도구로, 웹사이트를 탐색하고 페이지의 구조와 링크를 파악하여 데이터를 수집함.</p>
<ol start="26">
<li>입력 데이터의 보안 약점</li>
</ol>
<ul>
<li>크로스사이트 스크립트 : 검증되지 않은 외부 입력 값에 의해 브라우저에서 악의적인 코드가 실행</li>
<li>운영체제 명령어 삽입 : 운영체제 명령어 파라미터 입력 값이 적절한 사전검증을 거치지 않고 사용되어 공격자가 운영체제 명령어를 조작</li>
<li>SQL 삽입 : 사용자의 입력 값 등 외부 입력 값이 SQL 쿼리에 삽입되어 공격</li>
<li>자원 삽입 :  자원을 조작할 수 있는 문자열을 삽입해 시스템이 보호하는 자원에 임의로 접급할 수 있는 취약점</li>
</ul>
<p>27.FAT와 NFAT
FAT</p>
<ul>
<li>DOS때부터 사용되던 윈도우의 파일시스템</li>
<li>저용량에 적합, 호환성이 좋음,  저장가능한 파일의 최대크기가 4GB</li>
</ul>
<p>NTFS
    - FAT시스템을 대체하기 위해 개발된 윈도우 파일 시스템
    - 사용자마다 다른 보안 적용 가능 즉 보안이 FAT보다 뛰어남
    - 대용량 저장 가능 및 안정성이 뛰어남</p>
<ol start="28">
<li>리눅스의 파일 생성 권한 
리눅스의 초기 권환을 설정할 때 파일인 경우 666/ 디렉터리 일경우 777에서 해당 값을 빼면됨. 뺐을 때 앞자리가 0이면 0을 붙이는 것이 umask값임.</li>
</ol>
<ol start="30">
<li>로그파일
wtmp</li>
</ol>
<ul>
<li>성공한 로그인/로그아웃 정보를 담고 있는 로그파일</li>
<li>var/log/wtmp에 위치</li>
<li>last 명령어 사용
1,2,3 전부 없는 명령어이다. 
utmp</li>
<li>현재 로그인 사용자 상태 정보를 담고 있는 로그파일
btmp</li>
<li>실패한 로그인 정보를 담고 있는 로그파일
last log</li>
<li>마지막으로 성공한 로그인 정보를 담고있는 로그파일</li>
</ul>
<ol start="31">
<li><p>상향식 비용 산정 기법 중 LOC(원시 코드 라인 수) 기법에서 예측치 구하는 항목 
낙관치, 비관치, 기대치(낙비기)
예측치 구하는 방법 : (낙관치+비관치+기대치*4)/6</p>
</li>
<li><p>PLCP(Physical Layer Convergence Procedure : 물리계층 수렴 처리)</p>
<ul>
<li>논리적인 802.11 MAC 부계층과 물리적인 특성을 연결하는 역할</li>
<li>802.11 MAC 부계층이 물리적 특성에 관계없이 동작하도록 함
Traffic Distributor</li>
<li>네트워크 통신 간에 트래픽을 분배해주는 솔루션
DPI(Deep Packet Inspection 내부 분석)</li>
<li>네트워크에서 전송되는 패킷의 헤더와 페이로드 내 정보를 분석하는 컨텐츠 내용 분석 기술</li>
<li>네트워크 보안, 관리, 컨텐츠 관리 등이 목적</li>
</ul>
</li>
<li><p>나선형 모델(Spiral Model) </p>
</li>
</ol>
<ul>
<li>소프트웨어 개발 프로세스를 위험 관리(Risk Management) 측면에서 본 모델이다.</li>
<li>시스템을 여러 부분으로 나누어 여러 번의 개발 주기를 거치면서 시스템이 완성된다.</li>
<li>요구사항이나 아키텍처를 이해하기 어렵다거나 중심이 되는 기술에 문제가 있는 경우 적합한 모델이다.</li>
<li>점진적으로 개발이 반복되기에 위험분석 및 계획 수립 이후 추가적 위험 분석이 가능하다.</li>
</ul>
<ol start="34">
<li>소프트 웨어 생명주기 모델 중 V모델
: 소프트웨어 개발 프로세스로 폭포수 모델의 확장된 형태 중 하나로 볼 수 있다</li>
</ol>
<ul>
<li>폭포수 모델의 변형 </li>
<li>작업과 결과 검증에 초점을 둠</li>
<li>Perry에 의해 제안, 세부적인 테스트 과정으로 구성돼 신뢰도 높은 시스템 개발에 효과적</li>
</ul>
<p>검증(Verification)단계</p>
<ol>
<li><p>요구사항 분석</p>
</li>
<li><p>시스템 설계</p>
</li>
<li><p>아키텍처 설계</p>
</li>
<li><p>모듈 설계</p>
</li>
<li><p>개념찾기! 두둥
&lt;문제 해설&gt;
StackGuard</p>
</li>
</ol>
<ul>
<li>Stack 상에 일정한 주소번지에 프로그램이 선언한 canary를 심어 두어, 스택의 변조 된 경우에, canary를 체크하여 프로그램이 비정상적으로 종료 시키는 기법
(비정상적으로 종료)
Docker</li>
<li>컨테이너 응용프로그램의 배포를 자동화 하는 오픈소스 엔진</li>
<li>SW 컨터에이너 안의 응용 프로그램들을 배치시키는 일을 자동화해 주는 오픈소스 프로젝트 이자 소프트웨어
(배포자동화 + 소프트웨어)
Cipher Container</li>
<li>자바에서 암호화 복호화 기능을 제공하는 컨테이너
Scytale</li>
<li>암호화 기법으로 단순하게 문자열의 위치를 바꾸는 방법</li>
</ul>
<ol start="36">
<li>DES는 64비트의 암호화 알고리즘이지만 7비트마다 오류검출을 위한 정보가 들어가기에 실질적인 것은 56비트임. 
즉, 블록크기는 64비트 키 길이는 56비트 </li>
</ol>
<p>AES는 암호화 알고리즘은 
AES-128, AES-192, AES-256로 나뉘어지며 숫자는 비트수!</p>
<ol start="37">
<li>소프트 웨어 개발방법론의 테일러링 (Tailoring)
프로젝트 상황 특성에 맞게 정의된 소프트웨어 개발 방법론 절차, 사용기법 등을 수정 및 보완하는 작업</li>
</ol>
<ul>
<li>프로젝트에 최적화된 개발 방법론을 적용하기 위해 절차, 산출물 등을 적절히 변경하는 활동이다. </li>
<li>관리 측면에서의 목적 중 하나는 최단기간에 안정적인 프로젝트 진행을 위한 사전 위험을 식별하고 제거하는 것이다. </li>
<li>기술적 측면에서의 목적 중 하나는 프로젝트에 최적화된 기술 요소를 도입하여 프로젝트 특성에 맞는 최적의 기법과 도구를 사용하는 것이다. </li>
</ul>
<ol start="38">
<li>정보 보안 시스템 </li>
</ol>
<ul>
<li>강제접근통제(Mandatory Access Control), 주체와 객체의 등급을 비교하여 접근 권한을 부여하는 방식
즉, 보안레이블에 기초해 높은 보안 수준을 요구하는 정보가 낮은 보안 수준의 주체에게 노출되지 않도록 하는 접근제어방법</li>
<li>임의접근통제(Discretionary Access Control), 접근하는 사용자의 신원에 따라 접근 권한을 부여하는 방식</li>
<li>사용자계정컨트롤(User Access Control), 프로그램에서 관리자 수준의 권한이 필요한 작업을 수행할 때 사용자에게 알려서 제어할 수 있도록 돕는 기능</li>
<li>자료별 접근통제(Data-Label Access Control &gt; Label-Based Access Control), 개별 행, 열에 대해 쓰기 권한, 읽기 권한을 가졌는지를 명확하게 결정하는 제어 방식</li>
</ul>
<ol start="39">
<li><p>오픈 소스 소프트 웨어 라이브러리
타조 =&gt; 하둡기반 데이터 웨어하우스 시스템
포스퀘어 =&gt; 위치기반 소셜 네트워크 서비스
템서플로=&gt; 구글브레인팀에서 제작해 공개한 머신러닝을 위한 오픈 소스 </p>
</li>
<li><p>PaaS-TA
한국지능정보사회진흥원(NIA)가 지원하는 개방형 클라우드 플랫폼입니다</p>
</li>
</ol>
<p>-&gt; 국내 IT 서비스 경쟁력 강화를 목표로 개발되었으며 인프라 제어 및 관리 환경, 실행 환경, 개발 환경, 서비스 환경, 운영환경으로 구성되어 있는 개방형 클라우드 컴퓨팅 플랫폼</p>
<p>클라우드 컴퓨팅 플랫폼 : Iaas(Infrastructure), Paas(platform), Saas(software), Baas(block chain)가 있음</p>
<ol start="41">
<li>정보 보안을 위한 접근 제어와 관련된 설명</li>
</ol>
<ul>
<li>적절한 권한을 가진 인가자만 특정 시스템이나 정보에 접근할 수 있도록 통제</li>
<li>시스템 및 네트워크에 대한 접근 제어의 가장 기본적인 수단은 IP와 서비스 포트</li>
<li>네트워크 장비에서 수행하는 IP에 대한 접근 제어로는 관리 인터페이스의 접근제어와 ACL(Access Control List) 등이 있음</li>
</ul>
<p>42.VLAN(Virtual Local Area Network)
물리적 배치와 상관없이 논리적으로 LAN을 구성하는 것 
=&gt; 보드캐스트 도메인을 구분할 수 있게 하는 기술! 접속된 장비들의 성능향상과 보안성을 증대하는 효과가 있음.</p>
<p>STP(Spanning Tree Protocol)
: 2개 이상의 스위치가 여러 경로로 연결될 때, 
무한 루프 현상을 막기 위해서 우선순위 따라 1개의 경로로만 통신하도록 하는 프로토콜</p>
<p>ARP(Address Resolution Protocol)
: 네트워크 상에서 IP 주소를 물리적 네트워크 주소로 대응(bind)시키기 위해 사용되는 프로토콜,
 (IP를 MAC주소로 바인딩)</p>
<ol start="43">
<li>비대칭 암호화 방식으로 소수를 활용한 암호화 알고리즘
REA</li>
</ol>
<p>DES,AES는 대칭키 암호화 
=&gt; 이게 맞는지 잘모르겠음.</p>
<p>  SMT </p>
<ol start="44">
<li>IT스토리지 기술중  소프트웨어 정의 스토리지 (Software-defined storage) (SDS) 
: 스토리지에 가상화를 적용, 소프트웨어로 전체 스토리지 자원을 관리하여 하나의 저장장치럼 사용할 수 있도록 하는 기법</li>
</ol>
<ol start="45">
<li><p>랜선웨어(RansomWare)
Ransom(몸값)과 Ware(제품)의 합성어로서 악성코드의 일종
암호키 없이 개별적으로 복호화하는 것은 불가능에 가까움
사이버 범죄!!! 금전요구!! 나빠!</p>
</li>
<li><p>MQTT 프로토콜 (Message Queuing Telemetry Transport) </p>
</li>
</ol>
<ul>
<li>IBM 개발</li>
<li>발행/구독 프로토콜</li>
<li>TCP/IP를 통해 실행되어 기본 네트워크 연결을 제공</li>
</ul>
<p>그렇다면 이건 무슨 뜻일까?</p>
<ul>
<li><p>MLFQ(=MFQ)(Multi Level Feedback Queue) : 짧은 작업이나 입출력 위주의 프로세스에 우선순위를 부여하는 선점형 스케줄링 기법</p>
</li>
<li><p>Zigbee : 홈 네트워크 및 무선 센서망에서 사용되는 기술로, 버튼 하나의 동작으로 집안 어느 곳에서나 전등 제어 및 홈 보안 시스템을 제어관리하는 가정 자동화를 목표로 출발하였음. </p>
</li>
</ul>
<ol start="47">
<li><p>SSO - Single Sign On 
: 여러시스템 중 하나의 시스템에 인증을 성공하면 다른 시스템의 접근 권한도 모두 얻는 방식을 말함.</p>
</li>
<li><p>salt 
: 시스템에 저장되는 패스워드들은 Hash 또는 암호화 알고리즘의 결과 값으로 저장되는데 그때 암호 공격을 막기 위해 다른 암호값으로 저장되도록 추가되는 값의 의미이다. 소금을 바친다~~ 암호공격을 막기위해 소금을 줄테야! 임</p>
</li>
<li><p>침입탐지 시스템(IDS : Intrusion Detection System)
이상탐지(Anomaly Detection) -&gt; Behavior, Statistical Detection로 불리며 평균적 시스템의 상태 기준으로 비정상적인 행위나 자원의 사용이 감지되면 이를 알려줌. 감지가 되었을때 알려주는것임.</p>
</li>
</ol>
<ul>
<li>HIDS(Host-Based Intrusion Detection)는 운영체제에 설정된 사용자 계정에 따라 어떤 사용자가 어떤 접근을 시도하고 어떤 작업을 했는지에 대한 기록을 남기고 추적한다.</li>
<li>NIDS(Network-Based Intrusion Detection System)로는 대표적으로 Snort가 있다.</li>
<li>외부 인터넷에 서비스를 제공하는 서버가 위치하는 네트워크인 DMZ(Demilitarized Zone)에는 IDS가 설치될 수 있다.</li>
</ul>
<ol start="50">
<li>COcomo model : 비용산정 방식(LOC 수학산정기법) (
Organic: 5만 라인 이하의 프로젝트에 적합, 소규모 팀이 개발에 사용
Semidetached: 30만 라인 이하의 프로젝트에 적합, 트랜잭션 처리시스템 등
Embeded: 30만 라인 이상의 프로젝트에 적합, 하드웨어가 포함된 실스간 시스템 등</li>
</ol>
<ul>
<li>Putnam 모델 : Rayleigh-Norden 곡선의 노력 분포도를 이용한 비용 산정 기법</li>
<li>기능 점수 모델 : 기능 점수를 산출하여 비용 산정</li>
</ul>
<p>51.waterfall Model 폭포수 모델</p>
<ul>
<li>고전적 생명주기 모델</li>
<li>요구사항의 변경이 어려움(각단계 결과가 확인되야 다음단계로 넘어갈 수 있음)</li>
<li>그래서 나선형 (Sprial model)로 폭포수 타입의 장점에 위험성 분석을 추가했다!</li>
</ul>
<ol start="52">
<li>나선형 모델(spiral Model)</li>
</ol>
<ul>
<li>비교적 대규모 시스템에 적합함</li>
<li>개발 순서는 계획 및 정의- 위험 분석 - 공학적 개발 - 고객평가 순임</li>
<li>소프트웨어 개발하면서 발생할 수 있는 위험을 관리하고 최소화하는 것 목적으로 함</li>
<li>여러번 개발과정을 거쳐 점진적으로 개발과정이 반복되기에 추가, 누락사항은 첨가가능함.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트(2)-캠핑쇼핑몰]]></title>
            <link>https://velog.io/@minni_/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B82-%EC%BA%A0%ED%95%91%EC%87%BC%ED%95%91%EB%AA%B0</link>
            <guid>https://velog.io/@minni_/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B82-%EC%BA%A0%ED%95%91%EC%87%BC%ED%95%91%EB%AA%B0</guid>
            <pubDate>Sun, 30 Jun 2024 20:44:21 GMT</pubDate>
            <description><![CDATA[<p>이번에는 조금 더 규모가 큰 캠핑쇼핑몰을 구현해보았다. 이전 신발쇼핑몰과 쇼핑몰에서 구현한것과 같이 마이페이지를 구현을 맡았는데 추가적으로 뱃지, 운전면허 등록ocr이 추가하여 마이페이지를 구현하였다.</p>
<p>&lt;전반적 쇼핑몰 구성&gt;</p>
<ul>
<li>회원가입(카카오,네이버,구글 api사용/ 일반로그인)</li>
<li>로그인, 로그아웃</li>
<li>마이페이지(회원정보수정, 프로필변경, 회원탈퇴, 운전면허 등록ocr)</li>
<li>뱃지</li>
<li>상품 목록, 조회</li>
<li>상품 대여/ 상품 구매</li>
<li>장바구니</li>
<li>관심상품</li>
<li>자유게시판</li>
<li>상품 구매</li>
<li>ai 경로 추천</li>
<li>관리자 페이지(리액트)</li>
</ul>
<p>&lt;기획의도&gt;
<img src="https://velog.velcdn.com/images/minni_/post/fa7b3b30-3d3f-46cb-a3d7-8d61e2528357/image.png" alt=""></p>
<p>내가 구현한 페이지 소개
<img src="https://velog.velcdn.com/images/minni_/post/46ad2428-6d1f-493a-8ef2-f91f7b8a6c20/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/minni_/post/591c8146-8555-4f06-8a95-56ffc6b5789b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/minni_/post/e17aafce-8efa-4040-867d-01e63eae9580/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/minni_/post/b9c6373c-1913-4836-aeaa-f4f8657215eb/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/minni_/post/2ef75a9e-22b3-4454-8f0c-bb69377f6301/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/minni_/post/0a206353-265c-4151-8006-2ce140a07543/image.png" alt=""></p>
<p>자세한 건 
<a href="https://github.com/LEECHUNGs/finalProject">https://github.com/LEECHUNGs/finalProject</a> 여기를 참고하세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트(1)-신발쇼핑몰]]></title>
            <link>https://velog.io/@minni_/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B81-%EC%8B%A0%EB%B0%9C%EC%87%BC%ED%95%91%EB%AA%B0</link>
            <guid>https://velog.io/@minni_/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B81-%EC%8B%A0%EB%B0%9C%EC%87%BC%ED%95%91%EB%AA%B0</guid>
            <pubDate>Sun, 30 Jun 2024 20:31:28 GMT</pubDate>
            <description><![CDATA[<p>학원에서 팀원들과 함께 쇼핑몰을 주제로 한 프로젝트를 진행하였다.</p>
<p>내가 맡은 부분은 회원가입/마이페이지였는데, 수료 후에 상품결제, 게시판, 상품 상세페이지도 시간되면 만들어보고 싶다.</p>
<p>코드를 넣어놨는데 빠져있는 부분도 있을거고 코드가 깔끔하지 않아서 참고만 하면 좋을 것 같다..!</p>
<p>&lt;전반적 쇼핑몰 구성&gt;</p>
<ul>
<li>회원가입(일반로그인)</li>
<li>로그인, 로그아웃</li>
<li>마이페이지(회원정보수정,회원탈퇴)</li>
<li>상품 목록, 조회</li>
<li>상품 구매(결제는 x)</li>
<li>장바구니</li>
<li>관심상품</li>
<li>관리자 페이지</li>
</ul>
<p>&lt;기획의도&gt;
<img src="https://velog.velcdn.com/images/minni_/post/01ef8d63-0e69-465d-a24b-824bf4134dfb/image.png" alt=""></p>
<p>&lt;내가 구현한 페이지&gt;</p>
<ul>
<li>회원가입
<img src="https://velog.velcdn.com/images/minni_/post/860b57a4-ad2a-43aa-8db5-4afb8c2f6a4b/image.png" alt="">
controller<pre><code class="language-java"></code></pre>
</li>
</ul>
<p>/**
     * 회원가입 페이지
     * 
     * @param status
     */
    @GetMapping(&quot;signup&quot;)
    public String signup() {
        return &quot;pages/user/signup&quot;;
    }</p>
<pre><code>/**
 * @param inputUser
 * @param ra
 */
@PostMapping(&quot;signup&quot;)
public String signup(User inputUser, @RequestParam(&quot;userAddress&quot;) String[] userAddress, RedirectAttributes ra) {

    int result = service.signup(inputUser, userAddress);

    String path = null;
    String message = null;

    if (result &gt; 0) {
        message = inputUser.getUserNickname() + &quot; 님 환영합니다&quot;;
        path = &quot;/&quot;;

    } else {
        message = &quot; 회원가입에 실패했습니다&quot;;
        path = &quot;signup&quot;;
    }

    ra.addFlashAttribute(&quot;message&quot;, message);
    return &quot;redirect:&quot; + path;

}</code></pre><pre><code>service
```java
/**
     * 회원 회원가입
     * 
     * @param inputUser
     * @param userAddress
     * @return result
     */

    int signup(User inputUser, String[] userAddress);
    /**
     * 유저 정보 중복 체크
     * 
     * @param input  : 체크하고자 하는 유저 정보
     * @param method : 체크하고자 하는 정보 (userId, userEmail, userName)
     * @return result : COUNT(*)
     */
    int check(String input, String method);
</code></pre><p>serviceImpl</p>
<pre><code class="language-java">/**
     * 회원 회원가입
     * 
     * @param inputUser
     */

    public int signup(User inputUser, String[] userAddress) {


        // 비밀번호 암호화
        if(!inputUser.getUserAddress().equals(&quot;,,&quot;)) {

            String address = String.join(&quot;^^^&quot; , userAddress);
            inputUser.setUserAddress(address);

        }else {
            inputUser.setUserAddress(null);
        }
            // 비밀번호 암호화
        String encPw = passwordEncoder.encode(inputUser.getUserPw()); 
        inputUser.setUserPw(encPw);

        return mapper.signup(inputUser);
    }
    /**
     * 유저 정보 중복 확인
     */
    @Override
    public int check(String input, String method) {

        Map&lt;String, String&gt; map = new HashMap&lt;&gt;();

        map.put(&quot;input&quot;, input);
        map.put(&quot;method&quot;, method);

        return mapper.check(map);
    }</code></pre>
<p>Mapper</p>
<pre><code class="language-java">/**
     * 회원 회원가입
     * 
     * @param inputUser
     * @return result
     */
    int signup(User inputUser);
</code></pre>
<p>mapper.xml</p>
<pre><code class="language-xml">&lt;!-- 회원가입 --&gt;
    &lt;insert id=&quot;signup&quot;&gt;
        INSERT INTO &quot;USER&quot; 
        VALUES(
            SEQ_USER_NO.NEXTVAL, 
            #{userId},
            #{userPw}, 
            #{userNickname}, 
            #{userName}, 
            #{userAddress}, 
            #{userTel}, 
            #{userEmail}, 
            DEFAULT,
            DEFAULT, 
            DEFAULT, 
            DEFAULT
        )
    &lt;/insert&gt;
    &lt;!-- 중복 체크 --&gt;
    &lt;select id=&quot;check&quot; resultType=&quot;_int&quot;&gt;
        SELECT COUNT(*)
        FROM &quot;USER&quot;
        WHERE 
            &lt;choose&gt;
                &lt;!-- 유저 아이디 --&gt;
                &lt;when test=&#39;method == &quot;userId&quot;&#39;&gt;
                    USER_ID = #{input}
                &lt;/when&gt;
                &lt;!-- 유저 닉네임 --&gt;
                &lt;when test=&#39;method == &quot;userNickname&quot;&#39;&gt;
                    USER_NICKNAME = #{input}
                &lt;/when&gt;
                &lt;!-- 유저 이메일 --&gt;
                &lt;when test=&#39;method == &quot;userEmail&quot;&#39;&gt;
                    USER_EMAIL = #{input}
                &lt;/when&gt;
                &lt;!-- 유저 실명 --&gt;
                &lt;when test=&#39;method == &quot;userName&quot;&#39;&gt;
                    USER_NAME = #{input}
                &lt;/when&gt;
                &lt;!-- 유저 비밀번호 --&gt;
                &lt;when test=&#39;method == &quot;userPw&quot;&#39;&gt;
                    USER_PW = #{input}
                &lt;/when&gt;
            &lt;/choose&gt;
    &lt;/select&gt;</code></pre>
<p>html</p>
<pre><code class="language-html">&lt;form action=&quot;/user/signup&quot; method=&quot;POST&quot; name=&quot;signupForm&quot; id=&quot;signupForm&quot;&gt;

      &lt;h3&gt;회원 정보&lt;/h3&gt;

      &lt;!-- 아이디 입력 --&gt;
      &lt;label for=&quot;userId&quot;&gt; &lt;span class=&quot;required&quot;&gt;*&lt;/span&gt; 아이디 &lt;/label&gt;
      &lt;div class=&quot;signup-input-area&quot;&gt;
        &lt;input
          type=&quot;text&quot;
          name=&quot;userId&quot;
          id=&quot;userId&quot;
          autocomplete=&quot;off&quot;
          placeholder=&quot;아이디를 입력해주세요&quot;
        /&gt;
      &lt;/div&gt;
      &lt;span class=&quot;signup-message&quot; id=&quot;idMessage&quot;
        &gt;영어,숫자,_로만 5~10글자&lt;/span
      &gt;
      &lt;br /&gt;

      &lt;!-- 이름 입력 --&gt;
      &lt;label for=&quot;userName&quot;&gt; &lt;span class=&quot;required&quot;&gt;&lt;/span&gt;이름 &lt;/label&gt;
      &lt;div class=&quot;signup-input-area&quot;&gt;
        &lt;input
          type=&quot;text&quot;
          name=&quot;userName&quot;
          id=&quot;userName&quot;
          autocomplete=&quot;off&quot;
          placeholder=&quot;이름을 입력해주세요.&quot;
        /&gt;
      &lt;/div&gt;
      &lt;span class=&quot;signup-message&quot; id=&quot;nameMessage&quot;&gt;한글로만 2~6글자&lt;/span&gt;

      &lt;br /&gt;

      &lt;!-- 닉네임 입력 --&gt;
      &lt;label for=&quot;userNickname&quot;&gt; &lt;span class=&quot;required&quot;&gt;*&lt;/span&gt;닉네임 &lt;/label&gt;
      &lt;div class=&quot;signup-input-area&quot;&gt;
        &lt;input
          type=&quot;text&quot;
          name=&quot;userNickname&quot;
          id=&quot;userNickname&quot;
          autocomplete=&quot;off&quot;
          placeholder=&quot;닉네임을 입력해주세요.&quot;
        /&gt;
      &lt;/div&gt;

      &lt;span class=&quot;signup-message&quot; id=&quot;nicknameMessage&quot;
        &gt;한글,영어,숫자로만 2~8글자&lt;/span
      &gt;
      &lt;br /&gt;

      &lt;!-- 비밀번호 입력 --&gt;
      &lt;label for=&quot;userPw&quot;&gt; &lt;span class=&quot;required&quot;&gt;*&lt;/span&gt;비밀번호 &lt;/label&gt;
      &lt;div class=&quot;signup-input-area&quot;&gt;
        &lt;input
          type=&quot;password&quot;
          name=&quot;userPw&quot;
          id=&quot;userPw&quot;
          placeholder=&quot;비밀번호를 입력해주세요.&quot;
          autocomplete=&quot;off&quot;
        /&gt;
      &lt;/div&gt;

      &lt;!-- 비밀번호 확인 입력 --&gt;
      &lt;label for=&quot;userPwConfirm&quot;&gt;
        &lt;span class=&quot;required&quot;&gt;*&lt;/span&gt;비밀번호 확인
      &lt;/label&gt;
      &lt;div class=&quot;signup-input-area&quot;&gt;
        &lt;input
          type=&quot;password&quot;
          name=&quot;userPwConfirm&quot;
          id=&quot;userPwConfirm&quot;
          placeholder=&quot;비밀번호를 일치하게 입력해주세요&quot;
          autocomplete=&quot;off&quot;
        /&gt;
      &lt;/div&gt;

      &lt;span class=&quot;signup-message&quot; id=&quot;pwMessage&quot;
        &gt;비밀번호는 최소 6자에서 16자까지, 영문자,숫자,특수문자 1글자를
        포함해야합니다.&lt;/span
      &gt;

      &lt;br /&gt;
      &lt;!-- 전화번호 입력 --&gt;
      &lt;label for=&quot;userTel&quot;&gt;
        &lt;span class=&quot;required&quot;&gt;전화번호&lt;/span&gt;
      &lt;/label&gt;
      &lt;div class=&quot;signup-input-area&quot;&gt;
        &lt;input
          type=&quot;text&quot;
          name=&quot;userTel&quot;
          id=&quot;userTel&quot;
          placeholder=&quot;전화번호를 입력해주세요(-없이 숫자만 입력)&quot;
          autocomplete=&quot;off&quot;
        /&gt;
      &lt;/div&gt;

      &lt;span class=&quot;signup-message&quot; id=&quot;telMessage&quot;&gt;&lt;/span&gt;

      &lt;br /&gt;
      &lt;!-- 이메일 입력 --&gt;
      &lt;label for=&quot;userEmail&quot;&gt; &lt;span class=&quot;required&quot;&gt;*&lt;/span&gt;이메일 &lt;/label&gt;

      &lt;div class=&quot;signup-input-area&quot;&gt;
        &lt;!-- form 전달용 input --&gt;
        &lt;input type=&quot;hidden&quot; name=&quot;userEmail&quot; id=&quot;inputEmail&quot; /&gt;

        &lt;input type=&quot;text&quot; class=&quot;domain&quot; id=&quot;userEmail&quot; /&gt; @
        &lt;input type=&quot;text&quot; name=&quot;inputDomain&quot; id=&quot;inputDomain&quot; /&gt;
        &lt;select title=&quot;이메일 도메인 선택&quot; id=&quot;domainList&quot;&gt;
          &lt;option selected disabled&gt;선택&lt;/option&gt;

          &lt;option value=&quot;naver.com&quot;&gt;네이버&lt;/option&gt;
          &lt;option value=&quot;gmail.com&quot;&gt;구글&lt;/option&gt;
          &lt;option value=&quot;daum.net&quot;&gt;다음&lt;/option&gt;
          &lt;option value=&quot;kh.co.kr&quot;&gt;KH&lt;/option&gt;
          &lt;option value=&quot;apple.com&quot;&gt;애플&lt;/option&gt;
          &lt;option value=&quot;kakao.com&quot;&gt;카카오&lt;/option&gt;
          &lt;option value=&quot;&quot;&gt;직접입력&lt;/option&gt;
        &lt;/select&gt;
        &lt;button id=&quot;sendAuthKeyBtn&quot; type=&quot;button&quot;&gt;인증번호 요청&lt;/button&gt;
      &lt;/div&gt;

      &lt;span class=&quot;signup-message&quot; id=&quot;emailMessage&quot;
        &gt;메일을 받을 수 있는 이메일을 입력해주세요.&lt;/span
      &gt;

      &lt;br /&gt;
      &lt;!-- 인증번호 입력 --&gt;
        &lt;label for=&quot;emailCheck&quot;&gt;
          &lt;span class=&quot;required&quot;&gt;*&lt;/span&gt; 인증번호
        &lt;/label&gt;

        &lt;div class=&quot;signup-input-area&quot;&gt;
          &lt;input
            type=&quot;text&quot;
            name=&quot;authKey&quot;
            id=&quot;authKey&quot;
            placeholder=&quot;인증번호 입력&quot;
            maxlength=&quot;6&quot;
            autocomplete=&quot;off&quot;
          /&gt;
          &lt;button id=&quot;checkAuthKeyBtn&quot; type=&quot;button&quot;&gt;인증하기&lt;/button&gt;
        &lt;/div&gt;

        &lt;span class=&quot;signup-message&quot; id=&quot;authKeyMessage&quot;&gt;&lt;/span&gt;

      &lt;br /&gt;
      &lt;!-- 주소 입력 --&gt;
      &lt;label for=&quot;userAddress&quot;&gt;&lt;span class=&quot;required&quot;&gt;주소&lt;/span&gt;&lt;/label&gt;
      &lt;div class=&quot;signup-input-area&quot;&gt;
        &lt;label for=&quot;userAddress&quot;&gt;주소&lt;/label&gt;
        &lt;div class=&quot;signUp-input-area&quot;&gt;
          &lt;input
            type=&quot;text&quot;
            name=&quot;userAddress&quot;
            placeholder=&quot;우편번호&quot;
            maxlength=&quot;6&quot;
            id=&quot;postcode&quot;
          /&gt;
          &lt;button type=&quot;button&quot; id=&quot;searchAddress&quot;&gt;검색&lt;/button&gt;
        &lt;/div&gt;
        &lt;div class=&quot;signUp-input-area&quot;&gt;
          &lt;input
            type=&quot;text&quot;
            name=&quot;userAddress&quot;
            placeholder=&quot;도로명/지번 주소&quot;
            id=&quot;address&quot;
          /&gt;
        &lt;/div&gt;
        &lt;div class=&quot;signUp-input-area&quot;&gt;
          &lt;input
            type=&quot;text&quot;
            name=&quot;userAddress&quot;
            placeholder=&quot;상세 주소&quot;
            id=&quot;detailAddress&quot;
          /&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;button&gt;취소&lt;/button&gt;
      &lt;button type=&quot;submit&quot; id=&quot;submitBtn&quot;&gt;가입하기&lt;/button&gt;
    &lt;/form&gt;</code></pre>
<p>js</p>
<pre><code class="language-js">//필수 항목 유효성 검사를 체크하기 위한 객체
const checkObj = {
  userId: false,
  userNickname: false,
  userPw: false,
  userPwConfirm: false,
  emailVal: false,
  authKey: false,
};

// // 이용약관 전체 동의 눌렀을 때 체크
// function selectAll(selectAll)  {
//   const agreeAll 
//        = document.getElementsByName(&#39;agree&#39;);

//   agreeAll.forEach((checkbox) =&gt; {
//     checkbox.checked = selectAll.checked;
//     checkObj.agreement = true;
//   })
// }
// let agreeAll 
//        = document.getElementsByName(&#39;agree&#39;);
// // //전체 동의 누르면 모든 값 체크 되게 하기
// agreeAll.addEventListener(&#39;change&#39;, (e) =&gt; {
//   // let agreeChk = document.querySelectorAll(&#39;input[name=agree]&#39;);
//   for(let i = 0; i &lt; agreeAll.length; i++){
//     if(!agreeAll.checked){ 
//       checkObj.agreement = false;
//     }else {
//       checkObj.agreement = true;
//     }
//   }
// });



//---------------------주소 다음 api ==&gt; 수정 필요---------------------
function execDaumPostCode() {
  new daum.Postcode({
    oncomplete: function (data) {
      // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.

      // 각 주소의 노출 규칙에 따라 주소를 조합한다.
      // 내려오는 변수가 값이 없는 경우엔 공백(&#39;&#39;)값을 가지므로, 이를 참고하여 분기 한다.
      var addr = &#39;&#39;; // 주소 변수
      var extraAddr = &#39;&#39;; // 참고항목 변수

      //사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
      if (data.userSelectedType === &#39;R&#39;) {
        // 사용자가 도로명 주소를 선택했을 경우
        addr = data.roadAddress;
      } else {
        // 사용자가 지번 주소를 선택했을 경우(J)
        addr = data.jibunAddress;
      }
      // 우편번호와 주소 정보를 해당 필드에 넣는다.
      document.getElementById(&#39;postcode&#39;).value = data.zonecode;
      document.getElementById(&#39;address&#39;).value = addr;
      // 커서를 상세주소 필드로 이동한다.
      document.getElementById(&#39;detailAddress&#39;).focus();
    },
  }).open();
}

// 주소 검색 버튼 클릭 시
document
  .querySelector(&#39;#searchAddress&#39;)
  .addEventListener(&#39;click&#39;, execDaumPostCode);

// Id 유효성 검사
const userId = document.querySelector(&#39;#userId&#39;);
const idMessage = document.querySelector(&#39;#idMessage&#39;);

userId.addEventListener(&#39;input&#39;, (e) =&gt; {
  if (userId.value.length === 0) {
    idMessage.innerText = &#39;아이디를 입력해주세요&#39;;
    idMessage.classList.add(&#39;error&#39;);
    idMessage.classList.remove(&#39;confirm&#39;);
    checkObj.userId = false;
    return;
  }

  const regExp = /^[a-z0-9]{5,10}$/;

  if (!regExp.test(userId.value)) {
    idMessage.innerText = &#39;유효하지 않는 아이디입니다.&#39;;
    idMessage.classList.add(&#39;error&#39;);
    idMessage.classList.remove(&#39;confirm&#39;);
    checkObj.userId = false;
    return;
  }

  idMessage.innerText = &#39;사용 가능한 아이디 입니다&#39;;
  idMessage.classList.add(&#39;confirm&#39;);
  idMessage.classList.remove(&#39;error&#39;);
  checkObj.userId = true;

  const inputId = e.target.value;
  fetch(&#39;/user/checkId&#39;, {
    method: &#39;post&#39;,
    headers: { &#39;Content-Type&#39;: &#39;application/json&#39; },
    body: inputId,
  })
    .then((resp) =&gt; resp.text())
    .then((result) =&gt; {
      if (result == 1) {
        idMessage.innerText = &#39;이미 사용중인 아이디 입니다&#39;;
        idMessage.classList.add(&#39;error&#39;);
        idMessage.classList.remove(&#39;confirm&#39;);
        checkObj.userId = false;
        return;
      }
      idMessage.innerText = &#39;사용 가능한 아이디 입니다&#39;;
      idMessage.classList.add(&#39;confirm&#39;);
      idMessage.classList.remove(&#39;error&#39;);
      checkObj.userId = true;
    });
});

// 이름 유효성 검사
const userName = document.querySelector(&#39;#userName&#39;);
const nameMessage = document.querySelector(&#39;#nameMessage&#39;);

userName.addEventListener(&#39;input&#39;, (e) =&gt; {
  const inputName = e.target.value;
  if (inputName.trim().length === 0) {
    nameMessage.innerText = &#39;&#39;;
    inputName.value = null;
    return;
  }
  const regExp = /^[가-힣]{2,6}$/;
  if (!regExp.test(inputName)) {
    nameMessage.innerText = &#39;유효한 이름 형식이 아닙니다&#39;;
    inputName.value = null;
    return;
  }

  nameMessage.innerText = &#39;유효한 이름형식입니다&#39;;

  return inputName.value;
});

//  닉네임 유효성 검사
const userNickname = document.querySelector(&#39;#userNickname&#39;);
const nicknameMessage = document.querySelector(&#39;#nicknameMessage&#39;);

userNickname.addEventListener(&#39;input&#39;, (e) =&gt; {
  if (userNickname.value.length === 0) {
    nicknameMessage.innerText = &#39;닉네임을 입력해주세요&#39;;
    nicknameMessage.classList.add(&#39;error&#39;);
    nicknameMessage.classList.remove(&#39;confirm&#39;);
    checkObj.userNickname = false;
    return;
  }

  const regExp = /^(?=.*[a-z0-9가-힣])[a-z0-9가-힣]{2,10}$/;

  if (!regExp.test(userNickname.value)) {
    nicknameMessage.innerText = &#39;유효하지 않는 닉네임입니다.&#39;;
    nicknameMessage.classList.add(&#39;error&#39;);
    nicknameMessage.classList.remove(&#39;confirm&#39;);
    checkObj.userNickname = false;
    return;
  }

  nicknameMessage.innerText = &#39;사용 가능한 닉네임 입니다&#39;;
  nicknameMessage.classList.add(&#39;confirm&#39;);
  nicknameMessage.classList.remove(&#39;error&#39;);
  checkObj.userNickname = true;

  const inputNickname = e.target.value;

  fetch(&#39;/user/checkNickname&#39;, {
    method: &#39;post&#39;,
    headers: { &#39;Content-Type&#39;: &#39;application/json&#39; },
    body: inputNickname,
  })
    .then((resp) =&gt; resp.text())
    .then((result) =&gt; {
      if (result == 1) {
        nicknameMessage.innerText = &#39;이미 사용중인 닉네임 입니다&#39;;
        nicknameMessage.classList.add(&#39;error&#39;);
        nicknameMessage.classList.remove(&#39;confirm&#39;);
        checkObj.userNickname = false;
        return;
      }
      nicknameMessage.innerText = &#39;사용 가능한 닉네임 입니다&#39;;
      nicknameMessage.classList.add(&#39;confirm&#39;);
      nicknameMessage.classList.remove(&#39;error&#39;);
      checkObj.userNickname = true;
    });
});

//  비밀번호 유효성 검사
const userPw = document.querySelector(&#39;#userPw&#39;);
const userPwConfirm = document.querySelector(&#39;#userPwConfirm&#39;);
const pwMessage = document.querySelector(&#39;#pwMessage&#39;);

const checkPw = () =&gt; {
  if (userPw.value === userPwConfirm.value) {
    pwMessage.innerText = &#39;비밀번호가 일치합니다&#39;;
    pwMessage.classList.add(&#39;confirm&#39;);
    pwMessage.classList.remove(&#39;error&#39;);
    checkObj.userPwConfirm = true;
    return;
  }

  pwMessage.innerText = &#39;비밀번호가 일치하지 않습니다&#39;;
  pwMessage.classList.add(&#39;error&#39;);
  pwMessage.classList.remove(&#39;confirm&#39;);
  checkObj.userPwConfirm = false;
};

userPw.addEventListener(&#39;input&#39;, (e) =&gt; {
  const inputPw = e.target.value;

  if (inputPw.trim().length === 0) {
    pwMessage.innerText =
      &#39;비밀번호는 최소 6자에서 16자까지, 영문자,숫자,특수문자를 포함해야합니다.&#39;;

    pwMessage.classList.remove(&#39;confirm&#39;, &#39;error&#39;);
    checkObj.userPw = false;
    userPw.value = &#39;&#39;;
    return;
  }

  const regExp = /^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^&amp;*?_]).{6,16}$/;

  if (!regExp.test(inputPw)) {
    pwMessage.innerText = &#39;비밀번호가 유효하지 않습니다.&#39;;
    pwMessage.classList.add(&#39;error&#39;);
    pwMessage.classList.remove(&#39;confirm&#39;);
    checkObj.userPw = false;
    return;
  }

  pwMessage.innerText = &#39;유효한 비밀번호 형식입니다&#39;;
  pwMessage.classList.add(&#39;confirm&#39;);
  pwMessage.classList.remove(&#39;error&#39;);
  checkObj.userPw = true;

  if (userPwConfirm.value.length &gt; 0) {
    checkPw();
  }
});

userPwConfirm.addEventListener(&#39;input&#39;, () =&gt; {
  if (checkObj.userPw) {
    checkPw();
    return;
  }
  checkObj.userPwConfirm = false;
});

// 이메일 유효성 검사
const userEmail = document.querySelector(&#39;#userEmail&#39;);
const inputDomain = document.querySelector(&#39;#inputDomain&#39;);
const emailMessage = document.querySelector(&#39;#emailMessage&#39;);
const domainList = document.querySelector(&#39;#domainList&#39;);

// 이메일 입력
userEmail.addEventListener(&#39;input&#39;, (e) =&gt; {
  if (
    e.target.value.trim().length == 0 ||
    inputDomain.value.trim().length == 0
  ) {
    emailMessage.innerText = &#39;이메일을 입력해주세요&#39;;
    return;
  }

  checkObj.emailVal = true;

  emailMessage.innerText = &#39;이메일을 입력 성공&#39;;
});

// 이메일 도메인 입력
inputDomain.addEventListener(&#39;input&#39;, (e) =&gt; {
  if (e.target.value.trim().length == 0 || userEmail.value.trim().length == 0) {
    emailMessage.innerText = &#39;이메일을 입력해주세요&#39;;
    return;
  }
  checkObj.emailVal = true;

  emailMessage.innerText = &#39;이메일을 입력 성공&#39;;
});

// 도메인 리스트
domainList.addEventListener(&#39;change&#39;, (e) =&gt; {
  const optionsValue = e.target.options[e.target.selectedIndex].value;
  inputDomain.value = optionsValue;

  if (!optionsValue == &#39;&#39;) {
    inputDomain.readOnly = true;
  } else {
    inputDomain.readOnly = false;
  }

  if (e.target.value.trim().length == 0 || userEmail.value.trim().length == 0) {
    emailMessage.innerText = &#39;이메일을 입력해주세요&#39;;
    return;
  }

  checkObj.emailVal = true;

  emailMessage.innerText = &#39;이메일 입력 성공&#39;;
  const emailVal = userEmail.value + &#39;@&#39; + inputDomain.value;
  console.log(emailVal);
});

// 이메일 인증번호
const sendAuthKeyBtn = document.querySelector(&#39;#sendAuthKeyBtn&#39;);
const authKey = document.querySelector(&#39;#authKey&#39;);
const checkAuthKeyBtn = document.querySelector(&#39;#checkAuthKeyBtn&#39;);
const authKeyMessage = document.querySelector(&#39;#authKeyMessage&#39;);
const emailVal = userEmail.value + &#39;@&#39; + inputDomain.value;
let authTimer;
const initMin = 4;
const initSec = 59;
const initTime = &#39;05:00&#39;;

let min = initMin;
let sec = initSec;

sendAuthKeyBtn.addEventListener(&#39;click&#39;, () =&gt; {
  checkObj.authKey = false;

  authKeyMessage.innerText = &#39;&#39;;
  const emailVal = userEmail.value + &#39;@&#39; + inputDomain.value;

  if (!checkObj.emailVal) {
    alert(&#39;유효한 이메일 작성 후 클릭해 주세요&#39;);
    return;
  }

  min = initMin;
  sec = initSec;

  clearInterval(authTimer);

  console.log(emailVal);

  fetch(&#39;/email/signup&#39;, {
    method: &#39;POST&#39;,
    headers: { &#39;Content-Type&#39;: &#39;application/json&#39; },

    body: emailVal,
  })
    .then((resp) =&gt; resp.text())
    .then((result) =&gt; {
      if (result == 1) {
        console.log(&#39;인증 번호 발송 성공&#39;);
        emailMessage.innerText =
          &#39;인증번호 발송에 성공했습니다 인증번호를 입력해주세요&#39;;
      } else {
        console.log(&#39;인증 번호 발송 실패&#39;);
        emailMessage.innerText = &#39;인증번호 발송에 실패했습니다&#39;;
      }
    });

  authKeyMessage.innerText = initTime;
  authKeyMessage.classList.remove(&#39;confirm&#39;, &#39;error&#39;);

  alert(&#39;인증번호를 발송하였습니다. 입력하신 이메일을 확인해주세요&#39;);

  authTimer = setInterval(() =&gt; {
    authKeyMessage.innerText = `${addZero(min)}:${addZero(sec)}`;
    if (min == 0 &amp;&amp; sec == 0) {
      checkObj.authKey = false;
      clearInterval(authTimer);
      authKeyMessage.classList.add(&#39;error&#39;);
      authKeyMessage.classList.remove(&#39;confirm&#39;);
      return;
    }
    if (sec == 0) {
      sec = 60;
      min--;
    }
    sec--;
  }, 1000);
});
function addZero(number) {
  if (number &lt; 10) return &#39;0&#39; + number;
  else return number;
}

// form 전달용 input
const inputEmail = document.querySelector(&#39;#inputEmail&#39;);

checkAuthKeyBtn.addEventListener(&#39;click&#39;, () =&gt; {
  if (min == 0 &amp;&amp; sec == 0) {
    alert(&#39;인증번호 입력 제한시간을 초과하였습니다!&#39;);
    return;
  }
  if (authKey.value.length != 6) {
    alert(&#39;인증번호를 정확히 입력해 주세요&#39;);
    return;
  }
  const obj = {
    email: userEmail.value + &#39;@&#39; + inputDomain.value,
    authKey: authKey.value,
  };

  fetch(&#39;/email/checkAuthKey&#39;, {
    method: &#39;POST&#39;,
    headers: { &#39;Content-Type&#39;: &#39;application/json&#39; },
    body: JSON.stringify(obj),
  })
    .then((resp) =&gt; resp.text())
    .then((result) =&gt; {
      if (result == 0) {
        alert(&#39;인증번호가 일치하지 않습니다!&#39;);
        checkObj.authKey = false;
        return;
      }
      clearInterval(authTimer);
      authKeyMessage.innerText = &#39;인증 되었습니다.&#39;;
      alert(&#39;인증이 완료되었습니다&#39;); // 5.8 자습때 이 내용 추가했음!
      authKeyMessage.classList.remove(&#39;error&#39;);
      authKeyMessage.classList.add(&#39;confirm&#39;);
      inputEmail.value = userEmail.value + &#39;@&#39; + inputDomain.value;
      checkObj.authKey = true;
    });
});

//전화번호 유효성 검사
const userTel = document.querySelector(&#39;#userTel&#39;);
const telMessage = document.querySelector(&#39;#telMessage&#39;);

userTel.addEventListener(&#39;input&#39;, (e) =&gt; {
  const regExp = /^01[0-9]{1}[0-9]{3,4}[0-9]{4}$/;
  const inputTel = e.target.value;

  if (!regExp.test(inputTel)) {
    telMessage.innerText = &#39;유효한 전화번호 형식으로 수정해주세요&#39;;
    telMessage.classList.add(&#39;error&#39;);
    telMessage.classList.remove(&#39;confirm&#39;);
    //e.preventDefault();
    return;
  }

  if (inputTel.trim().length &lt; 9) {
    telMessage.innerText = &#39;유효한 전화번호 형식이 아닙니다&#39;;
    telMessage.classList.add(&#39;error&#39;);
    telMessage.classList.remove(&#39;confirm&#39;);
    inputTel.value = null; //e.preventDefault();
    return;
  }

  telMessage.innerText = &#39;유효한 전화번호 형식입니다.&#39;;
  telMessage.classList.add(&#39;confirm&#39;);
  telMessage.classList.remove(&#39;error&#39;);
});

// 회원가입 버튼 클릭시 전체 유효성 검사 여부 확인
const signupForm = document.querySelector(&#39;#signupForm&#39;);
const submitBtn = document.querySelector(&#39;#submitBtn&#39;);

submitBtn.addEventListener(&#39;click&#39;, (e) =&gt; {
  for (let key in checkObj) {
    if (!checkObj[key]) {
      let str;
      switch (key) {
        case &#39;userId&#39;:
          str = &#39;필수항목을 작성해주세요&#39;;
          break;
        case &#39;userNickname&#39;:
          str = &#39;필수항목을 작성해주세요&#39;;
          break;
        case &#39;userPw&#39;:
          str = &#39;필수항목을 작성해주세요&#39;;
          break;
        case &#39;userPwConfirm&#39;:
          str = &#39;비밀번호가 일치하지 않습니다&#39;;
          break;
        case &#39;userEmail&#39;:
          str = &#39;필수항목을 작성해주세요&#39;;
          break;
        case &#39;authKey&#39;:
          str = &#39;인증번호를 입력하지 않았습니다&#39;;
          break;
      }

      alert(str);
      document.getElementById(key).focus(); //초점이동
      e.preventDefault(); // form 태그 기본 이벤트(제출) 막기
      return;
    }
  }
  signupForm.submit();
});</code></pre>
<ul>
<li>마이페이지
<img src="https://velog.velcdn.com/images/minni_/post/85960823-2351-4ace-bde3-c3fe83df35ad/image.png" alt="">
controller<pre><code class="language-java">/**
   * 마이페이지 페이지
   * 
   * @return
   */
  @GetMapping(&quot;myPage&quot;)
  public String myPage() {
      return &quot;pages/user/myPage&quot;;
  }
</code></pre>
</li>
</ul>
<pre><code>

html
```html
&lt;div class=&quot;pageMain&quot;&gt;
      &lt;div class=&quot;pageTitle&quot;&gt;
        안녕하세요
        &lt;div class=&quot;userNickname&quot;&gt;
          &lt;th:block th:text=&quot;${session.loginUser.userNickname}&quot;&gt;&lt;/th:block&gt;
        &lt;/div&gt;
        님
      &lt;/div&gt;

      &lt;div class=&quot;myPage-wrap&quot;&gt;
        &lt;div class=&quot;myPage-content userDetail&quot;&gt;
          &lt;div class=&quot;simpleBox&quot;&gt;
            &lt;img
              class=&quot;userIcon userIconMyPage&quot;
              th:src=&quot;@{/img/userIcon/} + ${session.loginUser.userIcon} + |.png|&quot;
              alt=&quot;userIcon&quot;
            /&gt;
            &lt;div&gt;
              아이디:
              &lt;th:block th:text=&quot;${session.loginUser.userId}&quot;&gt;&lt;/th:block&gt;
            &lt;/div&gt;
            &lt;div&gt;
              닉네임:
              &lt;th:block th:text=&quot;${session.loginUser.userName}&quot;&gt;&lt;/th:block&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;myPage-content userInfo&quot;&gt;
          &lt;div class=&quot;simpleBox myPageBox1&quot;&gt;
            &lt;button
              type=&quot;button&quot;
              class=&quot;btn btn-shoesing btnInfo&quot;
              data-bs-toggle=&quot;modal&quot;
              data-bs-target=&quot;#staticBackdrop&quot;
              id=&quot;updateProfile&quot;
            &gt;
              내정보 수정
            &lt;/button&gt;
            &lt;a href=&quot;/wishlist/info&quot; class=&quot;btn btn-shoesing btnInfo&quot;
              &gt;위시리스트&lt;/a
            &gt;
            &lt;!-- &lt;a href=&quot;&quot;&gt;내가 작성한 게시글&lt;/a&gt; --&gt;
            &lt;a href=&quot;/order/info&quot; class=&quot;btn btn-shoesing btnInfo&quot;&gt;주문 조회&lt;/a&gt;

          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;myPage-wrap&quot;&gt;
      &lt;div class=&quot;myPage-content&quot;&gt;
        &lt;div class=&quot;simpleBox myPageBox2&quot;&gt;
          &lt;button
            type=&quot;button&quot;
            class=&quot;btn btn-shoesing btnInfo&quot;
            data-bs-toggle=&quot;modal&quot;
            data-bs-target=&quot;#staticBackdrop&quot;
            id=&quot;updateProfile&quot;
          &gt;
            내정보 수정
          &lt;/button&gt;
          &lt;a href=&quot;/wishlist/info&quot; class=&quot;btn btn-shoesing btnInfo&quot;
            &gt;위시리스트&lt;/a
          &gt;
          &lt;!-- &lt;a href=&quot;&quot;&gt;내가 작성한 게시글&lt;/a&gt; --&gt;
          &lt;a href=&quot;/order/info&quot; class=&quot;btn btn-shoesing btnInfo&quot;&gt;주문 조회&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;form
      action=&quot;/user/checkCurrentPw&quot;
      method=&quot;post&quot;
      name=&quot;checkPwForm&quot;
      id=&quot;checkPwForm&quot;
    &gt;
      &lt;!-- 비밀번호 입력 모달창 --&gt;
      &lt;div
        class=&quot;modal fade&quot;
        id=&quot;staticBackdrop&quot;
        data-bs-backdrop=&quot;static&quot;
        data-bs-keyboard=&quot;false&quot;
        tabindex=&quot;-1&quot;
        aria-labelledby=&quot;staticBackdropLabel&quot;
        aria-hidden=&quot;true&quot;
      &gt;
        &lt;div class=&quot;modal-dialog&quot;&gt;
          &lt;div class=&quot;modal-content&quot;&gt;
            &lt;div class=&quot;modal-header&quot;&gt;
              &lt;h5 class=&quot;modal-title&quot; id=&quot;staticBackdropLabel&quot;&gt;
                비밀번호 입력
              &lt;/h5&gt;
              &lt;button
                type=&quot;button&quot;
                class=&quot;btn-close&quot;
                data-bs-dismiss=&quot;modal&quot;
                aria-label=&quot;Close&quot;
              &gt;&lt;/button&gt;
            &lt;/div&gt;
            &lt;div class=&quot;modal-body&quot;&gt;
              &lt;!-- 현재 비밀번호 입력--&gt;
              &lt;div class=&quot;update-input-area&quot;&gt;
                현재 비밀번호
                &lt;input
                  type=&quot;password&quot;
                  placeholder=&quot;비밀번호를 입력해주세요&quot;
                  id=&quot;inputPw&quot;
                  name=&quot;inputPw&quot;
                /&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;modal-footer&quot;&gt;
              &lt;button
                type=&quot;button&quot;
                class=&quot;btn btn-secondary&quot;
                data-bs-dismiss=&quot;modal&quot;
              &gt;
                취소
              &lt;/button&gt;
              &lt;button class=&quot;btn btn-primary&quot;&gt;확인&lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/form&gt;</code></pre><p>js</p>
<pre><code class="language-js">//비밀번호가 현재 입력한 값과 같은지 조회
// 모달창으로 나온 현재 비밀번호 클릭한 경우
const checkPwForm = document.querySelector(&quot;#checkPwForm&quot;);
const inputPw = document.querySelector(&quot;#inputPw&quot;);

checkPwForm.addEventListener(&quot;submit&quot;,e=&gt;{
     e.preventDefault();
    if(inputPw.value.trim().length == 0){
        alert(&#39;현재 비밀번호를 입력해주시기 바랍니다&#39;);
        e.preventDefault();
        return;
    }
    fetch(&quot;/user/checkCurrentPw&quot;, {
        method : &#39;POST&#39;,
        headers : { &#39;Content-Type&#39;: &#39;application/json; charset=utf-8&#39; },
        body : JSON.stringify({
            &#39;inputPw&#39; : inputPw.value
        })
    })
    .then(resp =&gt; resp.json())
    .then(result =&gt; {
        if(result == 0){
            alert(&#39;비밀번호가 일치하지 않습니다.&#39;);
            e.preventDefault();
            return;
        } else{
            window.location.href=&quot;/user/updateProfile&quot;;
        }
    })
})  </code></pre>
<ul>
<li><p>마이페이지 내 정보 수정
<img src="https://velog.velcdn.com/images/minni_/post/de4b089e-8876-473b-b786-32a6750e91d4/image.png" alt="">
controller</p>
<pre><code class="language-java">// 프로필 아이콘 변경하기
  @ResponseBody
  @PostMapping(&quot;changeIcon&quot;)
  public int changeIcon(HttpServletRequest request, @RequestBody Map&lt;String, String&gt; map) {
      log.info(&quot;map {}&quot;, map);
      HttpSession session = request.getSession();

      User loginUser = (User) session.getAttribute(&quot;loginUser&quot;);
      loginUser.setUserIcon(map.get(&quot;inputIcon&quot;));
      session.setAttribute(&quot;loginUser&quot;, loginUser);
      String userId = loginUser.getUserId();

      int result = service.changeIcon(userId, map.get(&quot;inputIcon&quot;));

      return result;
  }

</code></pre>
</li>
</ul>
<pre><code>@GetMapping(&quot;updateProfile&quot;)
public String setAddress(@SessionAttribute(&quot;loginUser&quot;) User loginUser, Model model) {

    // 주소만 꺼내옴
    String userAddress = loginUser.getUserAddress();

    // 주소가 있을 경우에만 동작
    if (userAddress != null) {

        String[] arr = null;
        log.info(userAddress);
        if (userAddress.equals(&quot;^^^^^^&quot;)) {
            arr = new String[3];
            arr[0] = &quot;&quot;;
            arr[1] = &quot;&quot;;
            arr[2] = &quot;&quot;;

        } else {

            arr = userAddress.split(&quot;\\^\\^\\^&quot;); // regEx : 정규표현식
        }

        log.info(Arrays.toString(arr));

        model.addAttribute(&quot;postcode&quot;, arr[0]);
        model.addAttribute(&quot;address&quot;, arr[1]);
        model.addAttribute(&quot;detailAddress&quot;, arr[2]);

    }

    // /templates/myPage/myPage-info.html로 forward
    return &quot;pages/user/updateProfile&quot;;
}

/**
 * 내정보 수정
 * 
 * @return
 */
@PostMapping(&quot;updateProfile&quot;)

public String updateProfile(User inputUser, @SessionAttribute(&quot;loginUser&quot;) User loginUser,
        @RequestParam(&quot;userAddress&quot;) String[] userAddress, RedirectAttributes ra) {

    log.info(&quot;inputUser {}&quot;, inputUser);
    log.info(&quot;userAddress {}&quot;, userAddress[0]);
    String userId = loginUser.getUserId();
    inputUser.setUserId(userId);

    int result = service.updateProfile(inputUser, userAddress);

    String message = null;

    if (result &gt; 0) {
        message = loginUser.getUserNickname() + &quot;님의 정보가 수정되었습니다&quot;;

        loginUser.setUserName(inputUser.getUserName());
        loginUser.setUserNickname(inputUser.getUserNickname());
        loginUser.setUserTel(inputUser.getUserTel());
        loginUser.setUserAddress(inputUser.getUserAddress());
        loginUser.setUserEmail(inputUser.getUserEmail());
    } else {
        message = loginUser.getUserNickname() + &quot;님의 정보 수정에 실패했습니다&quot;;

    }
    ra.addFlashAttribute(&quot;message&quot;, message);

    return &quot;redirect:updateProfile&quot;;

}</code></pre><pre><code>service
```java
/**
     * 유저 아이콘 변경하기
     * 
     * @param inputIcon
     * @param inputIcon2
     * @return
     */
    int changeIcon(String userId, String inputIcon);
    /**
     * 내정보 수정
     * 
     * @param inputUser
     * @return
     */</code></pre><p>serviceImpl</p>
<pre><code class="language-java">/**
     * 회원 아이콘 변경
     */
    @Override
    public int changeIcon(String userId, String inputIcon) {

        Map&lt;String, String&gt; map = new HashMap&lt;&gt;();
        map.put(&quot;userId&quot;, userId);
        map.put(&quot;inputIcon&quot;, inputIcon);

        return mapper.changeIcon(map);
    }
    /**
     * 내 정보 수정
     */
    @Override
    public int updateProfile(User inputUser, String[] userAddress) {


        if (inputUser.getUserAddress().equals(&quot;,,&quot;)) {

            inputUser.setUserAddress(null);
        } else {
            String address = String.join(&quot;^^^&quot;, userAddress);

            inputUser.setUserAddress(address);
        }

        return mapper.updateProfile(inputUser);
    }</code></pre>
<p>Mapper</p>
<pre><code class="language-java">/**
     * 회원 아이콘 변경
     * 
     * @param Map&lt;String, String&gt; map
     * @return
     */
    int changeIcon(Map&lt;String, String&gt; map);
    /** 회원 정보 수정
     * @param inputUser
     * @return
     */
    int updateProfile(User inputUser);</code></pre>
<p>mapper.xml</p>
<pre><code class="language-xml">&lt;!-- 회원 아이콘 변경 --&gt;
    &lt;update id=&quot;changeIcon&quot;&gt;
        UPDATE &quot;USER&quot; SET
        USER_ICON = #{inputIcon}
        WHERE USER_ID = #{userId}
    &lt;/update&gt;
    &lt;!-- 내 정보 수정 --&gt;
    &lt;update id=&quot;updateProfile&quot;&gt;
        UPDATE &quot;USER&quot; SET
        USER_NAME = #{userName},
        USER_NICKNAME= #{userNickname},
        USER_TEL= #{userTel},
        USER_ADDRESS= #{userAddress},
        USER_EMAIL= #{userEmail}
        WHERE USER_ID = #{userId}
    &lt;/update&gt;</code></pre>
<p>html</p>
<pre><code class="language-html">&lt;div class=&quot;myProfile-area&quot;&gt;
      &lt;h1&gt;내 정보 수정&lt;/h1&gt;
    &lt;/div&gt;

    &lt;!-- 프로필 사진 --&gt;
    &lt;div class=&quot;profile-image-area&quot; style=&quot;text-align: center; width: 100%&quot;&gt;
      &lt;p&gt;나의 프로필 사진&lt;/p&gt;
      &lt;img
        th:src=&quot;@{/img/userIcon/} + ${session.loginUser.userIcon} + |.png|&quot;
        class=&quot;userIcon myIcon&quot;
      /&gt;
      &lt;br /&gt;
      &lt;p style=&quot;text-align: center; width: 100%&quot;&gt;프로필 사진 변경&lt;/p&gt;
      &lt;div class=&quot;updateIconDiv&quot;&gt;
        &lt;button class=&quot;profileIcon&quot; value=&quot;shoesing&quot;&gt;
          &lt;img th:src=&quot;@{/img/userIcon/shoesing.png}&quot; class=&quot;userIconUpdate&quot; /&gt;
        &lt;/button&gt;
        &lt;button class=&quot;profileIcon&quot; value=&quot;userIcon1&quot;&gt;
          &lt;img th:src=&quot;@{/img/userIcon/userIcon1.png}&quot; class=&quot;userIconUpdate&quot; /&gt;
        &lt;/button&gt;
        &lt;button class=&quot;profileIcon&quot; value=&quot;userIcon2&quot;&gt;
          &lt;img th:src=&quot;@{/img/userIcon/userIcon2.png}&quot; class=&quot;userIconUpdate&quot; /&gt;
        &lt;/button&gt;
        &lt;button class=&quot;profileIcon&quot; value=&quot;userIcon3&quot;&gt;
          &lt;img th:src=&quot;@{/img/userIcon/userIcon3.png}&quot; class=&quot;userIconUpdate&quot; /&gt;
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;br /&gt; &lt;br /&gt;
    &lt;form
      action=&quot;updateProfile&quot;
      method=&quot;POST&quot;
      name=&quot;updateProfileForm&quot;
      id=&quot;updateProfileForm&quot;
    &gt;
      &lt;!-- 아이디 (수정x 보여지기만) --&gt;
      &lt;div class=&quot;update-input-area&quot;&gt;
        &lt;div class=&quot;form-floating&quot;&gt;
          &lt;input
            type=&quot;text&quot;
            class=&quot;form-control&quot;
            placeholder=&quot;수정할 이름을 입력해주세요&quot;
            th:value=&quot;${session.loginUser.userId}&quot;
            readonly
          /&gt;
          &lt;label for=&quot;loginPagePw&quot;&gt;아이디&lt;/label&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;!-- 이름 수정--&gt;
      &lt;div class=&quot;update-input-area&quot;&gt;
        &lt;div class=&quot;form-floating&quot;&gt;
          &lt;input
            type=&quot;text&quot;
            class=&quot;form-control&quot;
            id=&quot;updateName&quot;
            name=&quot;userName&quot;
            placeholder=&quot;수정할 이름을 입력해주세요&quot;
            th:value=&quot;${session.loginUser.userName}&quot;
          /&gt;
          &lt;label for=&quot;loginPagePw&quot;&gt;수정할 이름을 입력해주세요&lt;/label&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;span id=&quot;updateNameMessage&quot;&gt;&lt;/span&gt;

      &lt;!-- 닉네임 수정--&gt;
      &lt;div class=&quot;update-input-area&quot;&gt;
        &lt;div class=&quot;form-floating&quot;&gt;
          &lt;input
            type=&quot;text&quot;
            class=&quot;form-control&quot;
            th:value=&quot;${session.loginUser.userNickname}&quot;
            id=&quot;updateNickname&quot;
            name=&quot;userNickname&quot;
            placeholder=&quot;수정할 닉네임을 입력해주세요&quot;
          /&gt;
          &lt;label for=&quot;loginPagePw&quot;&gt;수정할 닉네임을 입력해주세요&lt;/label&gt;
        &lt;/div&gt;
        &lt;span id=&quot;updateNicknameMessage&quot;&gt;&lt;/span&gt;
      &lt;/div&gt;

      &lt;!-- 전화번호 수정--&gt;
      &lt;div class=&quot;update-input-area&quot;&gt;
        &lt;div class=&quot;form-floating&quot;&gt;
          &lt;input
            type=&quot;text&quot;
            class=&quot;form-control&quot;
            th:value=&quot;${session.loginUser.userTel}&quot;
            id=&quot;updateTel&quot;
            name=&quot;userTel&quot;
            placeholder=&quot;수정할 닉네임을 입력해주세요&quot;
          /&gt;
          &lt;label for=&quot;loginPagePw&quot;&gt;수정할 전화번호를 입력해주세요&lt;/label&gt;
        &lt;/div&gt;
        &lt;br /&gt;
        &lt;span id=&quot;updateTelMessage&quot;&gt;&lt;/span&gt;
      &lt;/div&gt;
      &lt;!-- 주소 입력 --&gt;
      &lt;label for=&quot;userAddress&quot;&gt;주소&lt;/label&gt;
      &lt;div class=&quot;signUp-input-area input-group&quot; style=&quot;display: flex&quot;&gt;
        &lt;input
          type=&quot;text&quot;
          name=&quot;userAddress&quot;
          placeholder=&quot;우편번호&quot;
          maxlength=&quot;6&quot;
          id=&quot;postcode&quot;
          th:value=&quot;${postcode}&quot;
          class=&quot;form-control&quot;
        /&gt;
        &lt;button
          type=&quot;button&quot;
          id=&quot;searchAddress&quot;
          class=&quot;btn btn-outline-secondary&quot;
          style=&quot;width: 170px&quot;
        &gt;
          검색
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;signUp-input-area&quot;&gt;
        &lt;input
          type=&quot;text&quot;
          name=&quot;userAddress&quot;
          placeholder=&quot;도로명/지번 주소&quot;
          id=&quot;address&quot;
          th:value=&quot;${address}&quot;
          class=&quot;form-control&quot;
        /&gt;
      &lt;/div&gt;
      &lt;div class=&quot;signUp-input-area&quot;&gt;
        &lt;input
          type=&quot;text&quot;
          name=&quot;userAddress&quot;
          placeholder=&quot;상세 주소&quot;
          id=&quot;detailAddress&quot;
          th:value=&quot;${detailAddress}&quot;
          class=&quot;form-control&quot;
        /&gt;
      &lt;/div&gt;
      &lt;br /&gt;
      &lt;!-- 이메일 입력 --&gt;

      &lt;div class=&quot;update-input-area&quot;&gt;
        &lt;div&gt;
          이메일
          &lt;div
            class=&quot;update-input-area input-group mb-3&quot;
            id=&quot;emailDiv&quot;
            style=&quot;pointer-events: none&quot;
          &gt;
            &lt;label for=&quot;updateEmail&quot; class=&quot;input-group-text&quot;&gt;
              &lt;span class=&quot;required&quot;&gt;*&lt;/span&gt;이메일
            &lt;/label&gt;
            &lt;input
              type=&quot;hidden&quot;
              class=&quot;email&quot;
              id=&quot;inputEmail&quot;
              name=&quot;userEmail&quot;
            /&gt;
            &lt;input
              type=&quot;text&quot;
              class=&quot;email form-control&quot;
              id=&quot;updateEmail&quot;
              th:value=&quot;${#strings.substringBefore(session.loginUser.userEmail,&#39;@&#39;)}&quot;
            /&gt;
            &lt;span class=&quot;input-group-text&quot;&gt;@&lt;/span&gt;
            &lt;input
              type=&quot;text&quot;
              id=&quot;updateDomain&quot;
              class=&quot;form-control&quot;
              th:value=&quot;${#strings.substringAfter(session.loginUser.userEmail,&#39;@&#39;)}&quot;
            /&gt;

            &lt;select
              title=&quot;이메일 도메인 선택&quot;
              id=&quot;domainList&quot;
              class=&quot;btn btn-outline-secondary&quot;
            &gt;
              &lt;option selected disabled&gt;선택&lt;/option&gt;
              &lt;option value=&quot;naver.com&quot;&gt;네이버&lt;/option&gt;
              &lt;option value=&quot;gmail.com&quot;&gt;구글&lt;/option&gt;
              &lt;option value=&quot;daum.net&quot;&gt;다음&lt;/option&gt;
              &lt;option value=&quot;kh.co.kr&quot;&gt;KH&lt;/option&gt;
              &lt;option value=&quot;apple.com&quot;&gt;애플&lt;/option&gt;
              &lt;option value=&quot;kakao.com&quot;&gt;카카오&lt;/option&gt;
              &lt;option value=&quot;&quot;&gt;직접입력&lt;/option&gt;
            &lt;/select&gt;
          &lt;/div&gt;

          &lt;!-- 이메일 변경 버튼 --&gt;
          &lt;button
            type=&quot;button&quot;
            class=&quot;btn btn-shoesing&quot;
            data-bs-toggle=&quot;modal&quot;
            data-bs-target=&quot;#staticBackdrop&quot;
            id=&quot;updateEmailBtn&quot;
          &gt;
            이메일 변경
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;!-- 이메일 변경 모달창 --&gt;
        &lt;div
          class=&quot;modal fade&quot;
          id=&quot;staticBackdrop&quot;
          data-bs-backdrop=&quot;static&quot;
          data-bs-keyboard=&quot;false&quot;
          tabindex=&quot;-1&quot;
          aria-labelledby=&quot;staticBackdropLabel&quot;
          aria-hidden=&quot;true&quot;
        &gt;
          &lt;div class=&quot;modal-dialog&quot;&gt;
            &lt;div class=&quot;modal-content&quot;&gt;
              &lt;div class=&quot;modal-header&quot;&gt;
                &lt;h5 class=&quot;modal-title&quot; id=&quot;staticBackdropLabel&quot;&gt;
                  이메일 변경
                &lt;/h5&gt;
                &lt;button
                  type=&quot;button&quot;
                  class=&quot;btn-close&quot;
                  data-bs-dismiss=&quot;modal&quot;
                  aria-label=&quot;Close&quot;
                &gt;&lt;/button&gt;
              &lt;/div&gt;
              &lt;div class=&quot;modal-body&quot;&gt;
                &lt;p&gt;변경할 이메일을 작성후 인증번호 요청 버튼을 눌러주세요&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;modal-footer&quot;&gt;
                &lt;button
                  type=&quot;button&quot;
                  class=&quot;btn btn-secondary&quot;
                  data-bs-dismiss=&quot;modal&quot;
                &gt;
                  확인
                &lt;/button&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;span class=&quot;signup-message&quot; id=&quot;emailMessage&quot;&gt;&lt;/span&gt;

        &lt;br /&gt;

        &lt;!--인증번호 요청 버튼 --&gt;
        &lt;div id=&quot;authKeyDiv&quot;&gt;
          &lt;button
            type=&quot;button&quot;
            class=&quot;btn btn-primary&quot;
            data-bs-toggle=&quot;modal&quot;
            data-bs-target=&quot;#exampleModal1&quot;
            id=&quot;sendAuthKeyBtn&quot;
            style=&quot;display: none&quot;
          &gt;
            인증번호 요청
          &lt;/button&gt;
        &lt;/div&gt;

        &lt;!-- 인증번호 입력하는 모달창 --&gt;
        &lt;div
          class=&quot;modal fade&quot;
          id=&quot;exampleModal1&quot;
          tabindex=&quot;-1&quot;
          aria-labelledby=&quot;exampleModalLabel1&quot;
          aria-hidden=&quot;true&quot;
        &gt;
          &lt;div class=&quot;modal-dialog&quot;&gt;
            &lt;div class=&quot;modal-content&quot;&gt;
              &lt;div class=&quot;modal-header&quot;&gt;
                &lt;h5 class=&quot;modal-title&quot; id=&quot;exampleModalLabel1&quot;&gt;
                  인증번호 요청
                &lt;/h5&gt;
                &lt;button
                  type=&quot;button&quot;
                  class=&quot;btn-close&quot;
                  data-bs-dismiss=&quot;modal&quot;
                  aria-label=&quot;Close&quot;
                &gt;&lt;/button&gt;
              &lt;/div&gt;
              &lt;div class=&quot;modal-body&quot;&gt;
                &lt;span class=&quot;required&quot;&gt;*&lt;/span&gt; 인증번호
                &lt;input
                  type=&quot;text&quot;
                  name=&quot;authKey&quot;
                  id=&quot;authKey&quot;
                  placeholder=&quot;인증번호 입력&quot;
                  maxlength=&quot;6&quot;
                  autocomplete=&quot;off&quot;
                /&gt;
                &lt;br /&gt;
                &lt;span class=&quot;update-message&quot; id=&quot;authKeyMessage&quot;&gt;&lt;/span&gt;
              &lt;/div&gt;
              &lt;div class=&quot;modal-footer&quot;&gt;
                &lt;button
                  type=&quot;button&quot;
                  class=&quot;btn btn-secondary&quot;
                  data-bs-dismiss=&quot;modal&quot;
                &gt;
                  취소
                &lt;/button&gt;
                &lt;button
                  type=&quot;button&quot;
                  class=&quot;btn btn-shoesing&quot;
                  id=&quot;checkAuthKeyBtn&quot;
                &gt;
                  인증하기
                &lt;/button&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;br /&gt;

      &lt;!-- 수정완료버튼, 취소버튼 --&gt;
      &lt;div
        class=&quot;profile-submit&quot;
        style=&quot;width: 100%; display: flex; justify-content: space-between&quot;
      &gt;
        &lt;button
          id=&quot;updateProfileBtn&quot;
          class=&quot;btn btn-shoesing-secondary&quot;
          style=&quot;width: 80%; height: 80px&quot;
        &gt;
          수정완료
        &lt;/button&gt;
        &lt;div style=&quot;width: 8px&quot;&gt;&lt;/div&gt;
        &lt;a
          href=&quot;/user/myPage&quot;
          id=&quot;cancleprofile&quot;
          class=&quot;btn btn-shoesing-secondary&quot;
          style=&quot;
            width: 20%;
            height: 80px;
            display: flex;
            justify-content: center;
            align-items: center;
          &quot;
          &gt;취소&lt;/a
        &gt;
      &lt;/div&gt;</code></pre>
<p>js</p>
<pre><code class="language-js">//프로필 사진 변경
const userIcon = document.querySelectorAll(&#39;.userIcon&#39;);
const profileIcon = document.querySelectorAll(&#39;.profileIcon&#39;);

profileIcon.forEach((i) =&gt; {
  i.addEventListener(&#39;click&#39;, (e) =&gt; {
    const inputIcon = i.value;
    fetch(&#39;/user/changeIcon&#39;, {
      method: &#39;post&#39;,
      headers: { &#39;Content-type&#39;: &#39;application/json&#39; },
      body: JSON.stringify({ inputIcon: inputIcon }),
    })
      .then((resp) =&gt; resp.text())
      .then((result) =&gt; {
        if (result &gt; 0) {
          console.log(&#39;성공&#39;);
          alert(&#39;프로필 사진이 변경되었습니다&#39;);
          userIcon.forEach((u) =&gt; {
            u.src = &#39;/img/userIcon/&#39; + inputIcon + &#39;.png&#39;;
            console.log(u.src);
          });
        } else {
          console.log(&#39;실패&#39;);
        }
      });
  });
});


/// 회원 정보 수정 페이지
//필수 항목 =&gt; 닉네임,이메일(이메일 변경했을 때 인증번호 필수)
const checkObj ={
  updateNickname : true,
  updateEmail : true,
};


// 이름 수정
const updateName = document.querySelector(&#39;#updateName&#39;);
const updateNameMessage = document.querySelector(&#39;#updateNameMessage&#39;);

// 이름 정규식
const regExp = /^[가-힣]{2,6}$/;
updateName.addEventListener(&#39;input&#39;, (e) =&gt; {
  if (!regExp.test(e.target.value)) {
    updateNameMessage.innerText = &#39;유효한 이름 형식이 아닙니다.&#39;;
    return;
  }
  updateNameMessage.innerText = &#39;&#39;;
  return e.target.value;
});


// 닉네임 수정 
const updateNickname = document.querySelector(&quot;#updateNickname&quot;);
const updateNicknameMessage = document.querySelector(&quot;#updateNicknameMessage&quot;);

// 닉네임정규식
updateNickname.addEventListener(&quot;input&quot;,(e)=&gt;{
const regExp = /^(?=.*[a-z0-9가-힣])[a-z0-9가-힣]{2,10}$/;
    if(!regExp.test(updateNickname.value)){
        updateNicknameMessage.innerText=&quot;유효하지 않는 닉네임입니다.&quot;;
        checkObj.updateNickname=false;
        return;
    }
    // 닉네임 중복 검사
    updateNicknameMessage.innerText=&quot;&quot;
    const inputNickname = e.target.value;
    fetch(&quot;/user/checkNickname&quot;,{
      method : &#39;POST&#39;,
      headers : {&#39;Content-Type&#39; : &#39;application/json&#39;},
      body : inputNickname,
    })
    .then(resp =&gt; resp.text())
    .then(result =&gt; {

      if (result == 1) {
        updateNicknameMessage.innerText = &#39;이미 사용중인 닉네임 입니다&#39;;
        checkObj.updateNickname = false;
        return;
      }
      updateNicknameMessage.innerText = &#39;사용가능한 닉네임 입니다&#39;;
      checkObj.updateNickname = true;
    });
});



// 전화번호 수정
const updateTel = document.querySelector(&quot;#updateTel&quot;);
const updateTelMessage = document.querySelector(&quot;#updateTelMessage&quot;);

// 전화번호 정규식
updateTel.addEventListener(&quot;input&quot;,(e)=&gt;{
    const regExp=/^01[0-9]{1}[0-9]{3,4}[0-9]{4}$/;
    if(!regExp.test(e.target.value)){
        updateTelMessage.innerText=&quot;유효한 전화번호 형식으로 수정해주세요&quot;;
        return;
    }
      updateTelMessage.innerText=&quot;&quot;;  
});




// 주소 수정
function execDaumPostCode() {
  new daum.Postcode({
    oncomplete: function (data) {
      // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.

      // 각 주소의 노출 규칙에 따라 주소를 조합한다.
      // 내려오는 변수가 값이 없는 경우엔 공백(&#39;&#39;)값을 가지므로, 이를 참고하여 분기 한다.
      var addr = &#39;&#39;; // 주소 변수
      var extraAddr = &#39;&#39;; // 참고항목 변수

      //사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
      if (data.userSelectedType === &#39;R&#39;) {
        // 사용자가 도로명 주소를 선택했을 경우
        addr = data.roadAddress;
      } else {
        // 사용자가 지번 주소를 선택했을 경우(J)
        addr = data.jibunAddress;
      }
      // 우편번호와 주소 정보를 해당 필드에 넣는다.
      document.getElementById(&#39;postcode&#39;).value = data.zonecode;
      document.getElementById(&#39;address&#39;).value = addr;
      // 커서를 상세주소 필드로 이동한다.
      document.getElementById(&#39;detailAddress&#39;).focus();
    },
  }).open();
}

// 주소 검색 버튼 클릭 시 
document
  .querySelector(&#39;#searchAddress&#39;)
  .addEventListener(&#39;click&#39;, execDaumPostCode);

// 주소 유효성

// // const userAddress = document.querySelectorAll(input[name:&quot;userAddress&quot;])



// const addr0 = userAddress[0].value.trim().length == 0;
// const addr1 = userAddress[1].value.trim().length == 0;
// const addr2 = userAddress[2].value.trim().length == 0;

// //모두 true 인 경우만 true 저장
// const result1 = addr0 &amp;&amp; addr1 &amp;&amp; addr2; //아무것도 입력안한 경우

// //모두 false 인 경우만 true 저장
// const result2 = !(addr0 || addr1 || addr2); //모두 다 입력한 경우

// //모두 입력 또는 모두 미입력이 아니면
// if( !(result1 || result2) ){
//     alert(&quot;주소를 모두 작성 또는 미작성 해주세요&quot;);
//     e.preventDefault();
// }


// 이메일 수정
const updateEmailBtn = document.querySelector(&quot;#updateEmailBtn&quot;);
const emailDiv = document.querySelector(&quot;#emailDiv&quot;);
const sendAuthKeyBtn = document.querySelector(&quot;#sendAuthKeyBtn&quot;);

// 이메일 변경 버튼 눌렀을 때 인증번호 버튼 나타나게하기
updateEmailBtn.addEventListener(&quot;click&quot;,e =&gt;{

  console.log(updateEmailBtn);
  emailDiv.setAttribute(&quot;style&quot;,&quot;pointer-events:auto&quot;); 

  sendAuthKeyBtn.setAttribute(&quot;style&quot;,&quot;display:block&quot;);
  updateEmailBtn.setAttribute(&quot;style&quot;,&quot;display : none&quot;);
  ;
})

// 이메일 유효성 
let updateEmail = document.querySelector(&quot;#updateEmail&quot;);
const updateDomain = document.querySelector(&quot;#updateDomain&quot;);
const domainList = document.querySelector(&quot;#domainList&quot;);
const emailMessage = document.querySelector(&quot;#emailMessage&quot;);

// 이메일 아이디 쓰는 부분 검사

updateEmail.addEventListener(&#39;input&#39;, (e) =&gt; {
  if (
    e.target.value.trim().length == 0 ||
    updateDomain.value.trim().length == 0
  ) {
    emailMessage.innerText = &#39;이메일을 입력해주세요&#39;;
    return;
  }
  emailMessage.innerText = &#39;이메일을 입력 성공&#39;;


});

// 이메일 도메인 쓰는 부분 바꿀때 나타나는 이벤트
updateDomain.addEventListener(&#39;change&#39;, (e) =&gt; {
  let updateEmail = document.querySelector(&quot;#updateEmail&quot;);
  if (e.target.value.trim().length == 0 || updateEmail.value.trim().length == 0) {

    emailMessage.innerText = &#39;이메일을 입력해주세요&#39;;

    return;
  }
  checkObj.updateEmail = true;
  emailMessage.innerText = &#39;이메일을 입력 성공&#39;;
});

// 도메인 option 바꿀때 이벤트
domainList.addEventListener(&#39;change&#39;, (e) =&gt; {
  const optionsValue = e.target.options[e.target.selectedIndex].value;
  updateDomain.value = optionsValue;

  if (!optionsValue == &#39;&#39;) {
    updateDomain.readOnly = true;
  } else {
    updateDomain.readOnly = false;
  }

  let updateEmail = document.querySelector(&quot;#updateEmail&quot;);
  if (e.target.value.trim().length == 0 || updateEmail.value.trim().length == 0) {

    emailMessage.innerText = &#39;이메일을 입력해주세요&#39;;
    return;
  }
  emailMessage.innerText = &#39;이메일 입력 성공&#39;;

  inputEmail.value = updateEmail.value + &#39;@&#39; + updateDomain.value;
  console.log(updateEmail);
});

// 이메일 인증번호 
const authKey = document.querySelector(&quot;#authKey&quot;);
const checkAuthKeyBtn = document.querySelector(&quot;#checkAuthKeyBtn&quot;);
const authKeyMessage = document.querySelector(&quot;#authKeyMessage&quot;);


let authTimer;
const initMin = 4;
const initSec = 59;
const initTime = &#39;05:00&#39;;

let min = initMin;
let sec = initSec;

// 인증번호 발생 클릭시 나타나는 이벤트
sendAuthKeyBtn.addEventListener(&#39;click&#39;, () =&gt; {
  checkObj.updateEmail = false;
  authKeyMessage.innerText = &#39;&#39;;

  let updateEmail = document.querySelector(&quot;#updateEmail&quot;);
  const inputEmail = updateEmail.value + &#39;@&#39; + updateDomain.value;


  if (updateEmail.value.length == 0 || updateDomain.value.length == 0) {
    alert(&#39;이메일 작성 후 클릭해 주세요&#39;);
    return;
  }

  min = initMin;
  sec = initSec;

  clearInterval(authTimer);

  // 인증번호 발송 비동기
  fetch(&#39;/email/signup&#39;, {
    method: &#39;POST&#39;,
    headers: { &#39;Content-Type&#39;: &#39;application/json&#39; },
    body: inputEmail,
  })
    .then((resp) =&gt; resp.text())
    .then((result) =&gt; {
      if (result == 1) {
        console.log(&#39;인증 번호 발송 성공&#39;);
        emailMessage.innerText =
          &#39;인증번호 발송에 성공했습니다 인증번호를 입력해주세요&#39;;
      } else {
        console.log(&#39;인증 번호 발송 실패&#39;);
        emailMessage.innerText = &#39;인증번호 발송에 실패했습니다&#39;;
      }

  });

  authKeyMessage.innerText = initTime;
  authKeyMessage.classList.remove(&#39;confirm&#39;, &#39;error&#39;);

  alert(&#39;인증번호를 발송하였습니다. 입력하신 이메일을 확인해주세요&#39;);

  authTimer = setInterval(() =&gt; {
    authKeyMessage.innerText = `${addZero(min)}:${addZero(sec)}`;
    if (min == 0 &amp;&amp; sec == 0) {
      checkObj.updateEmail = false;
      clearInterval(authTimer);
      authKeyMessage.classList.add(&#39;error&#39;);
      authKeyMessage.classList.remove(&#39;confirm&#39;);
      return;
    }
    if (sec == 0) {
      sec = 60;
      min--;
    }
    sec--;
  }, 1000);
});
function addZero(number) {
  if (number &lt; 10) return &#39;0&#39; + number;
  else return number;
}

const inputEmail = document.querySelector(&#39;#inputEmail&#39;);


checkAuthKeyBtn.addEventListener(&#39;click&#39;, () =&gt; {
  if (min == 0 &amp;&amp; sec == 0) {
    alert(&#39;인증번호 입력 제한시간을 초과하였습니다!&#39;);
    return;
  }

  const obj = {

    email: updateEmail.value + &#39;@&#39; + updateDomain.value,
    authKey: authKey.value,
  };

  fetch(&#39;/email/checkAuthKey&#39;, {
    method: &#39;POST&#39;,
    headers: { &#39;Content-Type&#39;: &#39;application/json&#39; },
    body: JSON.stringify(obj),
  })
    .then((resp) =&gt; resp.text())
    .then((result) =&gt; {
      if (result == 0) {
        alert(&#39;인증번호가 일치하지 않습니다!&#39;);
        return;
      }
      clearInterval(authTimer);
      authKeyMessage.innerText = &#39;인증 되었습니다.&#39;;

      inputEmail.value = updateEmail.value + &#39;@&#39; + updateDomain.value;
      checkObj.updateEmail =true;
    });
});

const updateProfileBtn = document.querySelector(&quot;#updateProfileBtn&quot;);
updateProfileBtn.addEventListener(&quot;click&quot;, (e) =&gt; { 
  inputEmail.value = updateEmail.value + &#39;@&#39; + updateDomain.value;
  console.log(updateEmail);
  // 닉네임이 입력되지 않았을때
  if(!checkObj.updateNickname){
    alert(&#39;닉네임 에러&#39;);
    updateNickname.focus();
    checkObj.updateNickname = false;
    e.preventDefault();
    return;
  }
  //이메일이 입력되지 않았을때
  if(!checkObj.updateEmail){
    //인증번호 요청 버튼이 클릭되는 경우에
    if(sendAuthKeyBtn.clicked){
      alert(&#39;인증번호에러&#39;)
      checkObj.updateEmail = false;
      e.preventDefault();
      return;
    }
    alert(&#39;이메일에러&#39;);
    checkObj.updateEmail = false;
    updateEmail.focus();

    return;
  } 
  updateProfileForm.submit();
})</code></pre>
<ul>
<li><p>비밀번호 변경
<img src="https://velog.velcdn.com/images/minni_/post/9e1bc2b9-afa9-4831-b9c6-d2ef88796107/image.png" alt="">
controller</p>
<pre><code class="language-java">/**
   * 입력한 비밀번호가 현재 비밀번호와 같은지 체크 (마이페이지에서 내 정보 수정 들어갈때)
   * 
   * @param userId
   * @param inputPw
   * @return result
   */
  @ResponseBody
  @PostMapping(value = &quot;checkCurrentPw&quot;, produces = &quot;application/json; charset=UTF-8&quot;)
  public int checkCurrentPw(HttpServletRequest request, @RequestBody Map&lt;String, Object&gt; reqMap) {

      HttpSession session = request.getSession();
      User loginUser = (User) session.getAttribute(&quot;loginUser&quot;);
      String userId = loginUser.getUserId();
      String inputPw = (String) reqMap.get(&quot;inputPw&quot;);

      int result = service.checkCurrentPw(userId, inputPw);

      return result;
  }
/**
   * 비밀번호 변경
   * 
   * @param request
   * @param paramMap
   * @return
   */
  @ResponseBody
  @PostMapping(value = &quot;changePw&quot;, produces = &quot;application/json; charset=UTF-8&quot;)
  public int changePw(HttpServletRequest request, @RequestBody Map&lt;String, Object&gt; paramMap) {

      HttpSession session = request.getSession();

      User loginUser = (User) session.getAttribute(&quot;loginUser&quot;);

      String userId = loginUser.getUserId();
      String currentPw = (String) paramMap.get(&quot;currentPw&quot;);
      String newPw = (String) paramMap.get(&quot;newPw&quot;);

      // 현재 비밀번호가 일치하는지 확인
      int result = service.checkCurrentPw(userId, currentPw);
      int result2 = 0;

      // 현재 비밀번호가 입력한 비밀번호와 일치하는 경우
      if (result != 0) {
          result2 = service.changePw(loginUser, newPw);
      }
      return result2;

  }</code></pre>
<p>service</p>
<pre><code class="language-java">/**
   * 입력한 비밀번호가 현재 비밀번호와 같은지 체크
   * 
   * @param userId
   * @param inputPw
   * @return
   */
  int checkCurrentPw(String userId, String inputPw);

  /**
   * 비밀번호 변경
   * 
   * @param loginUser
   * @param inputPw
   * @return
   */
  int changePw(User loginUser, String inputPw);</code></pre>
</li>
</ul>
<p>serviceImpl</p>
<pre><code class="language-java">/**
     * 비밀번호 변경
     */
    @Override
    public int changePw(User loginUser, String inputPw) {

        // 현재 비밀번호가 같은지 보기
        String currentPw = mapper.checkCurrentPw(loginUser.getUserId());

        if (passwordEncoder.matches(inputPw, currentPw)) {
            return 2;
        }


        // 변경한 비밀번호 암호화 처리해주기
        loginUser.setUserPw(passwordEncoder.encode(inputPw));

        User user = new User();

        user.setUserId(loginUser.getUserId());
        user.setUserPw(loginUser.getUserPw());

        return mapper.changePw(user);

    }
    // 비밀번호 맞는지 확인
    @Override
    public int checkCurrentPw(String userId, String inputPw) {

        String currentPw = mapper.checkCurrentPw(userId);

        if (!passwordEncoder.matches(inputPw, currentPw)) {
            return 0;
        }
        return 1;
    }</code></pre>
<p>Mapper</p>
<pre><code>/** 비밀번호가 입력한 값과 같은지 체크
     * @param userId
     * @return
     */
    String checkCurrentPw(String userId);

    /**
     * 비밀번호 변경
     * 
     * @param userId
     * @param inputPw
     * @return
     */
    int changePw(User user);</code></pre><p>mapper.xml</p>
<pre><code class="language-xml">&lt;!-- 회원 비밀번호가 입력한 비밀번호와 같은지 조회 --&gt;
    &lt;select id=&quot;checkCurrentPw&quot;&gt;
        SELECT USER_PW
        FROM &quot;USER&quot;
        WHERE USER_ID =#{userId}
        AND USER_DEL_FL =&#39;N&#39;
    &lt;/select&gt; 

    &lt;!-- 회원 비밀번호 변경 --&gt;
    &lt;update id=&quot;changePw&quot;&gt;
        UPDATE &quot;USER&quot; SET
        USER_PW = #{userPw}
        WHERE USER_ID = #{userId}
    &lt;/update&gt;</code></pre>
<p>html</p>
<pre><code class="language-html">&lt;!-- 비밀번호 변경 버튼 --&gt;
    &lt;div style=&quot;display: flex; margin-top: 10px&quot;&gt;
      &lt;div&gt;
        &lt;button
          type=&quot;button&quot;
          class=&quot;btn btn-shoesing&quot;
          data-bs-toggle=&quot;modal&quot;
          data-bs-target=&quot;#exampleModal2&quot;
        &gt;
          비밀번호 변경
        &lt;/button&gt;
        &lt;!-- 비밀번호 변경 모달창 --&gt;
        &lt;form
          action=&quot;/user/changePw&quot;
          method=&quot;POST&quot;
          id=&quot;updatePwForm&quot;
          name=&quot;updatePwForm&quot;
        &gt;
          &lt;div
            class=&quot;modal fade&quot;
            id=&quot;exampleModal2&quot;
            tabindex=&quot;-1&quot;
            aria-labelledby=&quot;exampleModalLabel2&quot;
            aria-hidden=&quot;true&quot;
          &gt;
            &lt;div class=&quot;modal-dialog modal-dialog-scrollable&quot;&gt;
              &lt;div class=&quot;modal-content&quot;&gt;
                &lt;div class=&quot;modal-header&quot;&gt;
                  &lt;h5 class=&quot;modal-title&quot; id=&quot;exampleModalLabel2&quot;&gt;
                    비밀번호 변경
                  &lt;/h5&gt;
                  &lt;button
                    type=&quot;button&quot;
                    class=&quot;btn-close&quot;
                    data-bs-dismiss=&quot;modal&quot;
                    aria-label=&quot;Close&quot;
                  &gt;&lt;/button&gt;
                &lt;/div&gt;
                &lt;div class=&quot;modal-body&quot;&gt;
                  &lt;label&gt;
                    변경할 비밀번호 입력
                    &lt;input
                      type=&quot;password&quot;
                      placeholder=&quot;변경할 비밀번호를 입력해주세요&quot;
                      id=&quot;newPw&quot;
                      name=&quot;newPw&quot;
                    /&gt;
                    &lt;br /&gt;
                    변경될 비밀번호 확인
                    &lt;input
                      type=&quot;password&quot;
                      placeholder=&quot;변경 비밀번호를 확인해주세요&quot;
                      id=&quot;newPwConfirm&quot;
                      name=&quot;newPwConfirm&quot;
                    /&gt;
                  &lt;/label&gt;
                  &lt;br /&gt;
                  &lt;span class=&quot;update-message&quot; id=&quot;updatePwMessage&quot;&gt;&lt;/span&gt;
                  &lt;br /&gt;
                &lt;/div&gt;
                &lt;div class=&quot;modal-footer&quot;&gt;
                  &lt;label&gt;
                    현재 비밀번호 입력
                    &lt;input
                      type=&quot;password&quot;
                      placeholder=&quot;비밀번호를 입력해주세요&quot;
                      id=&quot;currentPw&quot;
                      name=&quot;currentPw&quot;
                    /&gt;
                  &lt;/label&gt;
                  &lt;button
                    type=&quot;button&quot;
                    class=&quot;btn btn-secondary&quot;
                    data-bs-dismiss=&quot;modal&quot;
                  &gt;
                    취소
                  &lt;/button&gt;
                  &lt;button class=&quot;btn btn-primary&quot; id=&quot;changePwBtn&quot;&gt;변경&lt;/button&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/form&gt;
      &lt;/div&gt;</code></pre>
<p>js</p>
<pre><code class="language-js">//비밀번호 변경
const newPw = document.querySelector(&#39;#newPw&#39;);
const newPwConfirm = document.querySelector(&#39;#newPwConfirm&#39;);
const updatePwMessage = document.querySelector(&#39;#updatePwMessage&#39;);
const currentPw = document.querySelector(&#39;#currentPw&#39;);

const checkUpdatePw = () =&gt; {
  if (newPw.value == newPwConfirm.value) {
    updatePwMessage.innerText = &#39;&#39;;
    updatePwMessage.innerText = &#39;비밀번호가 일치합니다&#39;;
    return;
  }
  updatePwMessage.innerText = &#39;비밀번호가 일치하지 않습니다&#39;;
};

newPw.addEventListener(&#39;input&#39;, (e) =&gt; {
  const inputNewPw = e.target.value;

  if (inputNewPw.trim().length == 0) {
    updatePwMessage.innerText =
      &#39;비밀번호는 최소 6자에서 16자까지, 영문자,숫자,특수문자를 포함해야합니다.&#39;;
    newPw.value = &#39;&#39;;
    return;
  }

  if (newPwConfirm.value.trim().length == 0) {
    updatePwMessage.innerText = &#39;변경할 비밀번호를 한번 더 입력해주세요&#39;;
    return;
  }
  const regExp = /^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^&amp;*?_]).{6,16}$/;

  if (!regExp.test(inputNewPw)) {
    updatePwMessage.innerText = &#39;비밀번호가 유효하지 않습니다.&#39;;

    return;
  }

  updatePwMessage.innerText = &#39;유효한 비밀번호 형식입니다&#39;;
  if (newPwConfirm.value.length &gt; 0) {
    checkUpdatePw();
  }
});

newPwConfirm.addEventListener(&#39;input&#39;, () =&gt; {
  if (newPw.value.length !== 0) {
    checkUpdatePw();
    return;
  }
});

// 비밀번호 변경 ajax
const updatePwForm = document.querySelector(&#39;#updatePwForm&#39;);

updatePwForm.addEventListener(&#39;submit&#39;, (e) =&gt; {
  e.preventDefault();

  if (currentPw.value.trim() == 0) {
    alert(&#39;현재 비밀번호를 입력해 주세요.&#39;);
    e.preventDefault();
    return;
  }
  fetch(&#39;/user/changePw&#39;, {
    method: &#39;POST&#39;,
    headers: { &#39;Content-Type&#39;: &#39;application/json; charset=utf-8&#39; },
    body: JSON.stringify({
      currentPw: currentPw.value,
      newPw: newPw.value,
    }),
  })
    .then((resp) =&gt; resp.json())
    .then((result) =&gt; {
      if (result == 0) {
        alert(&#39;현재 비밀번호가 일치하지 않습니다.&#39;);
        e.preventDefault();
        return;
      }
      if (result == 2) {
        alert(&#39;현재 비밀번호와 변경된 비밀번호가 일치합니다.&#39;);
        e.preventDefault();
        return;
      }
      if (result == 1) {
        alert(&#39;비밀번호가 변경되었습니다.&#39;);
        window.location.href = &#39;/user/myPage&#39;;
      }
    });
});</code></pre>
<ul>
<li><p>회원 탈퇴
<img src="https://velog.velcdn.com/images/minni_/post/4d74848a-12b8-4ab0-bc60-a94addac3c14/image.png" alt="">
controller</p>
<pre><code class="language-java">/**
   * 회원 탈퇴
   * 
   * @param request
   * @param ra
   * @return
   */
  @PostMapping(&quot;delete&quot;)
  public String delete(HttpServletRequest request, RedirectAttributes ra, SessionStatus status) {
      // 현재 세션
      HttpSession session = request.getSession();

      User loginUser = (User) session.getAttribute(&quot;loginUser&quot;);

      if (loginUser == null) { // 세션은 존재하지만 로그인한 회원은 존재하지 않을 경우
          ra.addFlashAttribute(&quot;message&quot;, &quot;로그인한 유저가 존재하지 않습니다&quot;);

          return &quot;redirect:/&quot;;
      }

      int result = service.delete(loginUser.getUserId());

      // 성공 시
      if (result &gt; 0) {

          // 세션 만료 (로그아웃)
          status.setComplete();

          ra.addFlashAttribute(&quot;message&quot;, &quot;성공적으로 탈퇴가 완료되었습니다&quot;);

          return &quot;redirect:/&quot;;
      }

      // 이외의 방법으로 실패 시
      ra.addFlashAttribute(&quot;message&quot;, &quot;실패&quot;);

      return &quot;redirect:/&quot;;
  }
  /**
   * 회원 탈퇴 시 입력한 값과 현재 비밀번호 일치하는지 체크
   * 
   * @param userId
   * @param inputPw
   * @return result
   */
  @ResponseBody
  @PostMapping(&quot;checkPw&quot;)
  public int checkPw(HttpServletRequest request, @RequestBody String inputPw) {

      HttpSession session = request.getSession();
      User loginUser = (User) session.getAttribute(&quot;loginUser&quot;);
      String userId = loginUser.getUserId();

      int result = service.checkCurrentPw(userId, inputPw);

      return result;

  }
</code></pre>
</li>
</ul>
<pre><code>service
```java
/**
     * 회원 탈퇴
     */
    int delete(String userId);

    /**
     * 입력한 비밀번호가 현재 비밀번호와 같은지 체크
     * 
     * @param userId
     * @param inputPw
     * @return
     */
    int checkCurrentPw(String userId, String inputPw);</code></pre><p>serviceImpl</p>
<pre><code class="language-java">/**
     * 회원 탈퇴
     */
    @Override
    public int delete(String userId) {
        return mapper.delete(userId);
    }</code></pre>
<p>Mapper</p>
<pre><code class="language-java">/** 비밀번호가 입력한 값과 같은지 체크
     * @param userId
     * @return
     */
    String checkCurrentPw(String userId);

    /**
     * 회원 탈퇴
     * 
     * @param userId
     * @return
     */
    int delete(String userId);</code></pre>
<p>mapper.xml</p>
<pre><code class="language-xml">&lt;!-- 회원 비밀번호가 입력한 비밀번호와 같은지 조회 --&gt;
    &lt;select id=&quot;checkCurrentPw&quot;&gt;
        SELECT USER_PW
        FROM &quot;USER&quot;
        WHERE USER_ID =#{userId}
        AND USER_DEL_FL =&#39;N&#39;
    &lt;/select&gt; 
&lt;!-- 회원 탈퇴 --&gt;
    &lt;update id=&quot;delete&quot;&gt;
        UPDATE &quot;USER&quot; SET
        USER_DEL_FL = &#39;Y&#39;
        WHERE USER_ID = #{userId}
    &lt;/update&gt;</code></pre>
<p>html</p>
<pre><code class="language-html">&lt;!-- 회원탈퇴 --&gt;
      &lt;div&gt;
        &lt;button
          type=&quot;button&quot;
          class=&quot;btn btn-shoesing&quot;
          data-bs-toggle=&quot;modal&quot;
          data-bs-target=&quot;#exampleModal&quot;
          style=&quot;margin-left: 8px&quot;
        &gt;
          회원탈퇴
        &lt;/button&gt;

        &lt;div
          class=&quot;modal fade&quot;
          id=&quot;exampleModal&quot;
          tabindex=&quot;-1&quot;
          aria-labelledby=&quot;exampleModalLabel&quot;
          aria-hidden=&quot;true&quot;
        &gt;
          &lt;div class=&quot;modal-dialog modal-dialog-scrollable&quot;&gt;
            &lt;div class=&quot;modal-content&quot;&gt;
              &lt;div class=&quot;modal-header&quot;&gt;
                &lt;h5 class=&quot;modal-title&quot; id=&quot;exampleModalLabel&quot;&gt;회원탈퇴&lt;/h5&gt;
                &lt;button
                  type=&quot;button&quot;
                  class=&quot;btn-close&quot;
                  data-bs-dismiss=&quot;modal&quot;
                  aria-label=&quot;Close&quot;
                &gt;&lt;/button&gt;
              &lt;/div&gt;
              &lt;div class=&quot;modal-body&quot;&gt;
                &lt;h1&gt;회원탈퇴 이용규약&lt;/h1&gt;
                &lt;br /&gt;

                &lt;br /&gt;
                제1조 (회원탈퇴에 따른 제한)
                &lt;br /&gt;&lt;br /&gt;
                “회원”이 탈퇴하는 경우 3개월간 재가입이 제한됩니다. 다만
                “고객사”가 “회사”에 “회원”의 재가입을 요청하는 경우에는 3개월
                이내에도 재가입이 가능합니다. “회원”이 탈퇴하는 경우, “회원 “이
                보유한 쿠폰, 마일리지는 모두 삭제됩니다. “회원”의 미결제 금액 및
                환불 금액이 존재하는 경우, 탈퇴 후 반환 처리됩니다. 제2조
                (개인정보 및 위치정보 보유) “회원”이 이용계약을 해지하는 경우,
                “회사”는 관련법령 및 개인정보처리방침에 따라 “회원”의 개인정보
                등을 보유하는 경우를 제외하고 해지 즉시 “회원”의 모든 정보를
                삭제합니다.
                &lt;br /&gt;&lt;br /&gt;
                다만 “회원”이 탈퇴하거나 자격을 상실할 경우에도 불구하고,
                “회사”는 [회사 내부 방침], [관계법령]에 따라 아래의 기간동안
                개인정보 및 위치정보를 보유할 수 있습니다.
                &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
                [회사 내부 방침에 의한 정보 보유]
                &lt;br /&gt;&lt;br /&gt;
                개인화 프로파일은 서비스 이용 종료 후 5년 또는 동의 철회 시까지
                (단, 관계법령의 별도의 규정이 명시되어 있는 경우 그 기간을 따름)
                농기계 작동/상태 정보, 사용 이력 정보, 진단 정보, 소모품 관리
                정보 및 개인 위치 정보는 수집 · 이용 목적 달성 시 또는 동의 철회
                시까지 요금 결제 및 정산이 완료되지 않은 경우 요금 결제 및 정산
                완료 시까지 고객의 불만/민원 처리, 소송 등 분쟁이 진행 중이거나
                예상되는 경우 처리 완료 시까지 수집된 개인 정보의 마케팅 및
                광고를 위한 이용은 회원 탈퇴 또는 동의 철회 시까지
                &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
                [관계법령에 의한 정보 보유]
                &lt;br /&gt;&lt;br /&gt;
                전자상거래 등에서의 「소비자 보호에 관한 법률」 에 따른 계약
                내용 및 이행 등 거래에 관한 기록
                &lt;br /&gt;
                계약 또는 청약 철회 등에 관한 기록 : 5년
                &lt;br /&gt;
                대금 결제 및 재화 등의 공급에 관한 기록 : 5년
                &lt;br /&gt;
                소비자의 불만 또는 분쟁 처리에 관한 기록 : 3년
                &lt;br /&gt;
                「상법」 에 따른 회사의 상업 장부와 영업에 관한 중요 서류 및
                전표 등에 관련된 정보 상업 장부 및 영업에 관한 중요 서류 : 10년
                &lt;br /&gt;
                전표 또는 이와 유사한 서류: 5년
                &lt;br /&gt;&lt;br /&gt;
                「국세기본법」, 「법인세법」 에 따른 모든 거래에 관한 장부 및
                증빙 서류와 관련된 정보 : 그 거래 사실이 속하는 과세 기간에 대한
                해당 국세의 법정 신고 기한이 지난 날부터 5년 「부가가치세법」 에
                따른 장부와 교부한 세금 계산서 또는 영수증 : 5년 「신용정보의
                이용 및 보호에 관한 법률」 에 따른 신용 정보의 수집·처리 및 이용
                등에 관한 기록 : 3년 개인정보를 제공받은 제3자는 제공 목적을
                달성하거나 이용자의 철회 요청이 있더라도, 내부보고, 감사 및
                검사, 비용 정산 (청구) 등 계약이행, 분쟁 대비를 위해 필요한
                정보는 서비스 이용 종료 후 6개월까지, 미이행·분쟁이 계속될 경우
                이행 완료·분쟁 해결 시까지 개인정보를 보유·이용할 수 있으며,
                아래의 제공받는 자의 보유 및 이용기간과 상법 등 관련 법령에
                특별한 규정에 따른 기간 동안 개인정보 및 위치정보를 보관할 수
                있습니다.
              &lt;/div&gt;
              &lt;div class=&quot;modal-footer&quot;&gt;
                &lt;form action=&quot;delete&quot; method=&quot;POST&quot; id=&quot;signoutForm&quot;&gt;
                  동의&lt;input type=&quot;checkbox&quot; id=&quot;agreeSignout&quot; /&gt;
                  &lt;br /&gt;
                  &lt;label&gt;
                    비밀번호 확인
                    &lt;input
                      type=&quot;password&quot;
                      placeholder=&quot;현재 비밀번호를 입력해주세요&quot;
                      id=&quot;currentPwConfirm&quot;
                    /&gt;
                    &lt;br /&gt;
                    &lt;span id=&quot;currentPwConfirmMessage&quot;&gt;&lt;/span&gt;
                  &lt;/label&gt;
                  &lt;br /&gt;
                  &lt;br /&gt;
                  &lt;button
                    type=&quot;button&quot;
                    class=&quot;btn btn-secondary&quot;
                    data-bs-dismiss=&quot;modal&quot;
                  &gt;
                    취소
                  &lt;/button&gt;
                  &lt;button class=&quot;btn btn-primary&quot; id=&quot;signupBtn&quot;&gt;탈퇴&lt;/button&gt;
                &lt;/form&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;</code></pre>
<p>js</p>
<pre><code class="language-js">// 회원 탈퇴 (성공!)

const checkSignout = {
  agreeSignout: false,
  currentPwConfirm: false,
};

const currentPwConfirm = document.querySelector(&#39;#currentPwConfirm&#39;);
const agreeSignout = document.querySelector(&#39;#agreeSignout&#39;);
const currentPwConfirmMessage = document.querySelector(
  &#39;#currentPwConfirmMessage&#39;
);
const signoutBtn = document.querySelector(&#39;#signoutBtn&#39;);

const signoutForm = document.querySelector(&#39;#signoutForm&#39;);

// 비밀번호 입력 시 이벤트
currentPwConfirm.addEventListener(&#39;input&#39;, () =&gt; {
  if (currentPwConfirm.value.trim().length == 0) {
    currentPwConfirmMessage.innerText = &#39;비밀번호를 입력해주세요&#39;;
    checkSignout.currentPwConfirm = false;
    return;
  }

  const inputPw = currentPwConfirm.value;
  fetch(&#39;/user/checkPw&#39;, {
    method: &#39;POST&#39;,
    headers: {
      &#39;Content-Type&#39;: &#39;application/json&#39;,
    },
    body: inputPw,
  })
    .then((resp) =&gt; resp.text())
    .then((result) =&gt; {
      if (result == 0) {
        currentPwConfirmMessage.innerText = &#39;비밀번호 불일치&#39;;
        checkSignout.currentPwConfirm = false;
        return;
      }
      currentPwConfirmMessage.innerText = &#39;비밀번호 일치&#39;;
      checkSignout.currentPwConfirm = true;
    });
});

// 동의체크박스
agreeSignout.addEventListener(&#39;change&#39;, (e) =&gt; {
  console.log(e.target.checked);
  if (e.target.checked) checkSignout.agreeSignout = true;
  else checkSignout.agreeSignout = false;
});

// 최종 서브밋 될 때 이벤트
signoutForm.addEventListener(&#39;submit&#39;, (e) =&gt; {
  if (!checkSignout.agreeSignout) {
    e.preventDefault();
    alert(&#39;탈퇴 약관에 동의해주세요&#39;);
    return;
  }

  if (!checkSignout.currentPwConfirm) {
    e.preventDefault();
    alert(&#39;비밀번호가 일치하지 않습니다&#39;);
    return;
  }

  alert(&#39;탈퇴 되었습니다!&#39;);
  return true;
});</code></pre>
<p>끝</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[GIT 꾸미기]]></title>
            <link>https://velog.io/@minni_/GIT-%EA%BE%B8%EB%AF%B8%EA%B8%B0</link>
            <guid>https://velog.io/@minni_/GIT-%EA%BE%B8%EB%AF%B8%EA%B8%B0</guid>
            <pubDate>Sun, 30 Jun 2024 19:52:06 GMT</pubDate>
            <description><![CDATA[<p>git 꾸며보기는 생각보다 간단하지않아보이는데 생각보다 간단하다!
잘모르겠으면 복붙하세요 :)</p>
<ol>
<li>프로필 이미지 만들기
나는 프로필 이미지를 아이폰 미모티콘으로도 만들었고, ZEPETO 어플로도 만들었다.
<img src="https://velog.velcdn.com/images/minni_/post/1b39949b-8dab-4835-9ce4-cf4408ab02eb/image.png" alt=""></li>
</ol>
<p><img src="https://velog.velcdn.com/images/minni_/post/a50d339d-f5d4-4d3a-b091-5b6ed840f5cb/image.png" alt=""></p>
<p>좀 더 밝고 예쁜걸로 선택했다 🫡</p>
<p>각자 취향에 맞게 프로필을 선택하면 될 것 같다!</p>
<ol start="2">
<li>repository만들기
<img src="https://velog.velcdn.com/images/minni_/post/1ccb7913-fbfc-4dfd-ba7f-6c5c9ea1510d/image.png" alt="">
여기서 new 클릭!</li>
</ol>
<p><img src="https://velog.velcdn.com/images/minni_/post/5659d7b1-d1b3-4452-98df-5489987b3fa4/image.png" alt="">
나는 이미 만들었기에 존재한다고 뜨지만 처음 생성하면 아마 가능할 것이다.
여기서 생성하기 누르기!</p>
<ol start="3">
<li>README 작성하기
<img src="https://velog.velcdn.com/images/minni_/post/0fd0b201-0cc4-4a83-810e-197630cb1485/image.png" alt="">
저기 연필 아이콘 눌러서 내용을 추가하면 된다. 참고하면 좋을 오픈소스,사이트 공유합니다.</li>
</ol>
<ul>
<li>헤더 오픈소스
<a href="https://github.com/kyechan99/capsule-render">https://github.com/kyechan99/capsule-render</a></li>
<li>기술 뱃지 제작 사이트
<a href="https://shields.io/">https://shields.io/</a></li>
<li>로고 제작 사이트
<a href="https://simpleicons.org/">https://simpleicons.org/</a></li>
<li>기술뱃지 오픈소스?
<a href="https://github.com/rzashakeri/beautify-github-profile">https://github.com/rzashakeri/beautify-github-profile</a></li>
<li>git state 오픈소스
<a href="https://github.com/anuraghazra/github-readme-stats">https://github.com/anuraghazra/github-readme-stats</a></li>
<li>방문자수 확인 사이트
<a href="https://hits.seeyoufarm.com">https://hits.seeyoufarm.com</a></li>
</ul>
<p>참고하여 내용 작성해주면 된다!</p>
<p>내가 작성한 코드는?</p>
<pre><code>&lt;!--헤더 부분--&gt;
![header](https://capsule-render.vercel.app/api?type=waving&amp;color=ffd700&amp;text=%20welcome%20to%20My%20Github&amp;height=200&amp;fontSize=50&amp;fontColor=ffffff)

&lt;!--내용 부분--&gt;
&lt;h4 align=&quot;center&quot;&gt;🙋‍♀️hello, My name is Lee MinKyung  &lt;br&gt;&lt;br&gt; 👩‍💻I hope to become a backend developer.&lt;/h4&gt;
&lt;br&gt;

&lt;h3 align=&quot;center&quot;&gt;
  ⌨️ Top Languages &lt;/h3&gt;
&lt;h3 align=&quot;center&quot;&gt;

![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=minnily&amp;layout=compact)
&lt;/h3&gt;
&lt;br&gt;
&lt;br&gt;

&lt;!--내용 부분--&gt;
&lt;h3 align=&quot;center&quot;&gt;🚩Tech Stack &lt;/h3&gt;
&lt;div align=&quot;center&quot;&gt;
  &lt;img src=&quot;https://img.shields.io/badge/react-20232a.svg?style=for-the-badge&amp;logo=react&amp;logoColor=61DAFB&quot; /&gt;&amp;nbsp
  &lt;img src=&quot;https://img.shields.io/badge/javascript-F7DF1E.svg?style=for-the-badge&amp;logo=javascript&amp;logoColor=20232a&quot; /&gt;&amp;nbsp
  &lt;img src=&quot;https://img.shields.io/badge/html5-E34F26.svg?style=for-the-badge&amp;logo=html5&amp;logoColor=white&quot; /&gt;&amp;nbsp
&lt;/div&gt;

&lt;div align=&quot;center&quot;&gt;
&lt;img src=&quot;https://img.shields.io/badge/css3-1572B6.svg?style=for-the-badge&amp;logo=css3&amp;logoColor=white&quot; /&gt;&amp;nbsp
  &lt;img src=&quot;https://img.shields.io/badge/java-007396?style=for-the-badge&amp;logo=OpenJDK&amp;logoColor=white&quot;/&gt;&amp;nbsp
&lt;/div&gt;

&lt;br&gt;

&lt;h3 align=&quot;center&quot;&gt;🪄Tools &lt;/h3&gt;
&lt;div align=&quot;center&quot;&gt;
  &lt;img src=&quot;https://img.shields.io/badge/git-F05033.svg?style=for-the-badge&amp;logo=git&amp;logoColor=white&quot; /&gt;&amp;nbsp
  &lt;img src=&quot;https://img.shields.io/badge/github-181717.svg?style=for-the-badge&amp;logo=github&amp;logoColor=white&quot; /&gt;&amp;nbsp
  &lt;img src=&quot;https://img.shields.io/badge/Notion-F3F3F3.svg?style=for-the-badge&amp;logo=notion&amp;logoColor=black&quot; /&gt;&amp;nbsp
  &lt;img src=&quot;https://img.shields.io/badge/figma-F24E1E.svg?style=for-the-badge&amp;logo=figma&amp;logoColor=white&quot; /&gt;&amp;nbsp
&lt;/div&gt;

&lt;div align=&quot;center&quot;&gt;
  &lt;img src=&quot;https://img.shields.io/badge/VSCode-2C2C32.svg?style=for-the-badge&amp;logo=visual-studio-code&amp;logoColor=22ABF3&quot; /&gt;&amp;nbsp
  &lt;img src=&quot;https://img.shields.io/badge/MySQL-4479A1?style=for-the-badge&amp;logo=MySQL&amp;logoColor=white&quot;/&gt;&amp;nbsp
  &lt;img src=&quot;https://img.shields.io/badge/springboot-6DB33F?style=for-the-badge&amp;logo=springboot&amp;logoColor=white&quot;/&gt;&amp;nbsp
&lt;/div&gt;

&lt;br&gt;

&lt;h3 align=&quot;center&quot;&gt;📩Contact💕&lt;/h3&gt;
&lt;div align=&quot;center&quot;&gt;
  &lt;a href=&quot;https://velog.io/@minni_&quot;&gt;
    &lt;img src=&quot;https://img.shields.io/badge/Velog-1EBC8F?style=for-the-badge&amp;logo=velog&amp;logoColor=white&quot; /&gt;&amp;nbsp
  &lt;/a&gt;
  &lt;a href=&quot;mailto:dlalsrud20142905@gmail.com&quot;&gt;
    &lt;img
      src=&quot;https://img.shields.io/badge/dlalsrud20142905@gmail.com-D14836?style=for-the-badge&amp;logo=gmail&amp;logoColor=white&quot;/&gt;&amp;nbsp
  &lt;/a&gt;
&lt;/div&gt;

&lt;!--footer 부분--&gt;
![footer](https://capsule-render.vercel.app/api?section=footer&amp;type=waving&amp;color=ffd700)</code></pre><p>그래서 완성은?</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/cd60d623-5ce0-4818-8c4b-959dcb4f007e/image.png" alt=""></p>
<p>정말 쉽죠? 😎 너도 할 수 있어요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React (3)]]></title>
            <link>https://velog.io/@minni_/React-2-Exam3</link>
            <guid>https://velog.io/@minni_/React-2-Exam3</guid>
            <pubDate>Tue, 04 Jun 2024 01:39:55 GMT</pubDate>
            <description><![CDATA[<h3 id="1-state-lifting-up--방법">1. State lifting up  방법</h3>
<p>State lifting up? 상태 끌어올리기를 말한다.
▶ 리액트에서는 부모 컴포넌트가 자식 컴포넌트의 상태를 직접 변경 할 수 없다
따라서,  자식에서 발생한 이벤트를 부모에서 처리하도록 하는 상태 끌어올리기 패턴을 이용해야한다.</p>
<p>해당 예제 파일에서는 컴포넌트 총 3개를 만들거다!!</p>
<p>1) Id 컴포넌트 (자식)
2) Pw 컴포넌트 (자식)
3) Exam3 컴포넌트 (부모) - 해당 파일에서 내보낼 기본 컴포넌트
이렇게!!!  </p>
<p>여기서 잠깐 !</p>
<pre><code class="language-js">function Id(){

} 

함수형 컴포넌트는 이렇게도 사용이 가능!

const Id= () =&gt; {

}</code></pre>
<p>💡 JSX 를 사용한 html작성부는 무조건 최상위 부모태그 하나로 감싸져 있어야한다.</p>
<pre><code>&lt;h1&gt;&lt;/h1&gt;</code></pre><p>이렇게 하나만은 사용가능하지만</p>
<pre><code>&lt;h1&gt;&lt;/h1&gt;
&lt;h1&gt;&lt;/h1&gt;</code></pre><p>인 경우 형제 요소로 되어 이를 모두 감싸는 최상위 태그가 꼭 필요하다!</p>
<pre><code>예를 들면 이렇게?!
&lt;&gt;
  &lt;h1&gt;&lt;/h1&gt;
  &lt;h1&gt;&lt;/h1&gt;
&lt;/&gt;</code></pre><p><strong>그렇다면 상태 끌어올리기 방법을 코드로 살펴보자</strong> 👩‍💻</p>
<pre><code class="language-js">import { useState } from &quot;react&quot;;

//Id 컴포넌트 (자식)
// ()안에 props를 작성 -&gt; 부모에게서 전달받은 속성을 props라고 부르는데 값을 받을 준비가 되어야하기에 작성필요!
// 매개변수 이름이 props이고 props : {onChangeId} 인 것임.
const Id = (props) =&gt; {
  const { onChangeId } = props; // props 안에 있는 onChangeId라는 이름의 함수를 이용할 수 있게 됨.

  //   const [id, setId] = useState(&quot;&quot;); // 상태(state) 중 &#39;id&#39;를 생성하고 초기값으로 &quot;&quot;을 설정
  return (
    // JSX를 사용한 html구문 작성부는 무조건 최상위 부모태그 하나로 감싸져 있어야 한다!

    &lt;&gt;
      &lt;div&gt;
        &lt;label&gt;ID :&lt;/label&gt;
        &lt;input onChange={onChangeId} /&gt;
        {/* onChange 이벤트 핸들러에 onChangeId를 연결함 */}
      &lt;/div&gt;
    &lt;/&gt;
  );
};</code></pre>
<pre><code class="language-js">//Pw 컴포넌트 (자식)
const Pw = ({ onChangePw }) =&gt; {
  // {}를 이용하여 props 안에 있는 값을 바로 꺼내서 쓸 수도 있다.

  //   const [pw, setPw] = useState(&quot;&quot;); // 상태(state) 중 &#39;pw&#39;를 생성하고 초기값으로 &quot;&quot;을 설정
  return (
    // JSX를 사용한 html구문 작성부는 무조건 최상위 부모태그 하나로 감싸져 있어야 한다!

    &lt;&gt;
      &lt;div&gt;
        &lt;label&gt;Pw :&lt;/label&gt;
        &lt;input onChange={onChangePw} /&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
};</code></pre>
<pre><code class="language-js">// Exam3컴포넌트 (부모)
const Exam3 = () =&gt; {
  // 자식의 상태를 부모에서 정의(상태 끌어올리기)
  const [id, setId] = useState(&quot;&quot;);
  const [pw, setPw] = useState(&quot;&quot;);

  // 자식의 상태를 변경할 수 있는 함수를 정의
  ////id 변경하는 함수 -&gt; 여기서 e는 input창에 작성하는 값을 e라고 지정
  const onChangeId = (e) =&gt; {
    //input창에 입력되는 값을 id로 변경해줄 것임
    setId(e.target.value);
  };

  // input창에 입력되는 값을 pw로 변경해줄 것임
  const onChangePw = (e) =&gt; {
    setPw(e.target.value);
  };

  return (
    &lt;&gt;
      {/* 컴포넌트 중 Id를 불러 렌더링 함 (Id가 Exam3의 자식이 됨) 
      자식 컴포넌트에는 (props)에는 전달만 가능하고 직접 넣는것은 어려움*/}
      &lt;Id onChangeId={onChangeId} /&gt;

      {/* 컴포넌트 중 Pw를 불러 렌더링 함 (Pw가 Exam3의 자식이 됨) */}
      &lt;Pw onChangePw={onChangePw} /&gt;

      &lt;div&gt;
        {/* button 의 disabled 속성 : 비활성화 속성 (비활성 true / 활성 false)
            -&gt; id 와 pw 둘 다 작성되어야 활성화
        */}
        {/* 현재 이렇게만 작성하면 id, pw를 인식하지 못하여 위 상단에 상태를 끌어올리기를 해야한다. 
        상태 끌어올린 후 이벤트 핸들러도 끌어올려줘야함
        id, pw에 input창을 넣어놨는데 리액트에서 상태를 인지할 수 있는 이벤트 핸들러를 만들어놔야한다.*/}
        &lt;button disabled={id.length === 0 || pw.length === 0}&gt;Login&lt;/button&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
};
export default Exam3;</code></pre>
<p><img src="https://velog.velcdn.com/images/minni_/post/a12afa22-724c-4ac2-9c91-d43e91a9b5c9/image.png" alt="">
비활성화 되었던 button이 입력 후 활성화 되는것을 볼 수 있음.</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/389486df-2778-4a1c-93e5-47cf6f60c233/image.png" alt=""></p>
<h3 id="2-props-drilling-방법">2. Props Drilling 방법!</h3>
<p>Props Drilling이란? 상태 내리 꽂기를 말한다!
▶ props를 통해 데이터를 전달할 때, 자식 컴포넌트에서 필요하지 않은 props를 계속해서 전달하는 행위</p>
<p>따라서 이러한 문제점으로 코드의 가독성 및 유지보수성을 떨어뜨린다...!</p>
<ul>
<li>대책: React Context API 나 Redux 같은 상태관리 라이브러리를 사용함</li>
</ul>
<p>Exam4 에서는 Child1 컴포넌트만 부를 것임, Child1 에서는 Child2 컴포넌트만 부르고, Child2 에서는 Child3 컴포넌트만 부르고, Child3 에서는 MyComponent 이런식으로 부를 것이다.
※ 이처럼 부모자식 관계가 연결되어 있을 때!!
Exam4의 상태값을 MyComponent에서 사용해야한다면? 어떻게 해야할까?</p>
<pre><code class="language-js">import { useState } from &quot;react&quot;;

// 부모 컴포넌트
function Exam4() {
  const [name, setName] = useState(&quot;홍길동&quot;);

  //클릭되면 네임 상태값 이름을 바꿀것이라는 함수
  const handleClick = () =&gt; {
    setName(&quot;손오공&quot;);
  };
  return (
    &lt;&gt;
      {/* Child1이라는 자식 컴포넌트 불러오고 전달할 값 넣기  여기서 name은 props!*/}
      &lt;Child1 name={name} /&gt;
      &lt;button onClick={handleClick}&gt;이름변경&lt;/button&gt;
    &lt;/&gt;
  );
}

// 자식 컴포넌트 Child1
//위에서 전달받은 props가 있기에 props를 작성해주면 된다.
function Child1(props) {
  // Child2에 props안에 있는 name을 전달한다는 뜻!
  return &lt;Child2 name={props.name} /&gt;;
}

// 자식 컴포넌트 Child2
//위에서 전달받은 props가 있기에 props를 작성해주면 된다.
function Child2(props) {
  // Child2에 props안에 있는 name을 전달한다는 뜻!
  return &lt;Child3 name={props.name} /&gt;;
}

// 자식 컴포넌트 Child3
//위에서 전달받은 props가 있기에 props를 작성해주면 된다.
function Child3(props) {
  // Child3에 props안에 있는 name을 전달한다는 뜻!
  return &lt;MyComponent name={props.name} /&gt;;
}

// 자식 컴포넌트 MyComponent
//위에서 전달받은 props가 있기에 props를 작성해주면 된다.
function MyComponent(props) {
  //props는 Exam4에서 부터 내리꽂기를 통해 전달받은 부모의 상태값
  return &lt;h1&gt;{props.name}&lt;/h1&gt;;
}

export default Exam4;</code></pre>
<p><img src="https://velog.velcdn.com/images/minni_/post/795714c8-db40-4da5-a64b-66dfe6275121/image.png" alt="">
이렇게 변경이 된다
<img src="https://velog.velcdn.com/images/minni_/post/cf0edd24-937a-4b3e-95d7-675bb210d669/image.png" alt=""></p>
<h3 id="3-전개연산자--사용법">3. 전개연산자 (...) 사용법</h3>
<p>: 객체 내부의 모든 값을 props로 전달하는 방법</p>
<pre><code class="language-js">

import { useState } from &quot;react&quot;;


// 부모
function Exam5() {
  // userState() 여기 상태값에 배열, 자바스크립트 객체 값도 전달 가능함!
  const [userData, setUserData] = useState({ name: &quot;홍길동&quot;, age: 30 });

  //...userData는 name ={userData.name} age={userData.age}로 상태값을 전달하는 것과 같음
  return &lt;MyComponent {...userData} /&gt;;
}

//자식
function MyComponent(props) {
  const { name, age } = props;

  const content = `안녕하세요 제 이름은 ${name} 이고, 나이는 ${age}세 입니다`;
  return &lt;h3&gt;{content}&lt;/h3&gt;;
}

export default Exam5;</code></pre>
<p>결과</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/5e869cbe-6506-4cc5-9571-b963a03ee159/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[sts사용시 외부 프로그램?에서 작성한 내용이 바로바로 적용이 안될때...?]]></title>
            <link>https://velog.io/@minni_/sts%EC%82%AC%EC%9A%A9%EC%8B%9C-%EC%99%B8%EB%B6%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8%EC%97%90%EC%84%9C-%EC%9E%91%EC%84%B1%ED%95%9C-%EB%82%B4%EC%9A%A9%EC%9D%B4-%EB%B0%94%EB%A1%9C%EB%B0%94%EB%A1%9C-%EC%A0%81%EC%9A%A9%EC%9D%B4-%EC%95%88%EB%90%A0%EB%95%8C</link>
            <guid>https://velog.io/@minni_/sts%EC%82%AC%EC%9A%A9%EC%8B%9C-%EC%99%B8%EB%B6%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8%EC%97%90%EC%84%9C-%EC%9E%91%EC%84%B1%ED%95%9C-%EB%82%B4%EC%9A%A9%EC%9D%B4-%EB%B0%94%EB%A1%9C%EB%B0%94%EB%A1%9C-%EC%A0%81%EC%9A%A9%EC%9D%B4-%EC%95%88%EB%90%A0%EB%95%8C</guid>
            <pubDate>Mon, 03 Jun 2024 12:35:19 GMT</pubDate>
            <description><![CDATA[<p>간단하지만 불편함으로 해결하지 못할때가 있는데..!
sts를 사용하면서 가끔 정말 가끔 ...
외부프로그램에서 사용한 것이 적용이 안되서 왜 안되는걸까 하고 설마...?하며 sts에 들어가 해당 파일을 열면 그때서야 새로고침이 되는 경우가 있지 않은가?????</p>
<p>매번 이런 문제가 있었는데 해결하고 안적어놔서 인지 까먹고 매번 왜그러지왜그러지 하며 불편을 감수하고 작업을 했던 기억이 있어서
이번엔 적어두고 잊지않으려고 한담.... 🫡</p>
<p>먼저 확인할 사항 1!</p>
<p>sts 상단에 보면 다양한 목록들이 있다 거기서 project를 찾는다!
<img src="https://velog.velcdn.com/images/minni_/post/9a2c51a8-6b13-4611-b421-b8b09ce28a81/image.png" alt=""></p>
<p>여기서 bulid Automatically가 체크가 되어 있는지 확인해준다 
안되어 있다면 꼭 체크 해주기!
<img src="https://velog.velcdn.com/images/minni_/post/7d7f16ef-f6c7-4808-a492-d232b24a9bfa/image.png" alt=""></p>
<p>체크가 되어있어도 안되는 경우? 2번째로 바로 들어가자!
<img src="https://velog.velcdn.com/images/minni_/post/9a2c51a8-6b13-4611-b421-b8b09ce28a81/image.png" alt="">
여기서 Window로 들어가서 preference를 찾아서 클릭!
<img src="https://velog.velcdn.com/images/minni_/post/283a5f32-b332-4293-bbe6-84c30148efd2/image.png" alt=""></p>
<p>그럼 이렇게 뜬다!
<img src="https://velog.velcdn.com/images/minni_/post/9ee753fa-9166-462a-a5e2-c6e3afa02dac/image.png" alt=""></p>
<p>여기서 General을 클릭하고 Workspace를 찾거나 검색창에 Workspace를 검색한다!</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/ac9906d3-3ca9-4acb-8ecb-c1bf635f466f/image.png" alt=""></p>
<p>여기서 바로바로 첫번째 부분 
Refresh using native hooks or polling에 체크가 되어있는지 살펴본다 
안되어 있다면 체크체크!
<img src="https://velog.velcdn.com/images/minni_/post/7fab9766-c9b9-4585-bda1-33175959c951/image.png" alt=""></p>
<p>그리고 아주아주 가끔은 XML부분에 체크가 안되있어도 안되기도 했던거 같은데 기억이 잘안나는데 일단 체크해보자.. 그럼 분명 될거다.. 추가될 부분이 있다면 댓글로 알려주세요! 
<img src="https://velog.velcdn.com/images/minni_/post/7e6d018a-bb93-4e8b-862c-7e835b159e46/image.png" alt=""></p>
<p>모두모두 해결하시길 바라며.. :) 안녕</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React (2)]]></title>
            <link>https://velog.io/@minni_/React-Component-%EC%98%88%EC%A0%9C1</link>
            <guid>https://velog.io/@minni_/React-Component-%EC%98%88%EC%A0%9C1</guid>
            <pubDate>Mon, 03 Jun 2024 02:02:17 GMT</pubDate>
            <description><![CDATA[<p>Component? </p>
<ul>
<li>React 앱의 구성 요소로, 재사용 가능하도록 만들어져 있으며 UI를 작은 조각으로 나누어 관리함.</li>
<li>컴포넌트 명은 보통 대문자로 작성함.</li>
</ul>
<p>Component 는 아래와 같이 두가지로 나뉨.</p>
<ol>
<li>클래스형 컴포넌트 : React.Component 클래스를 상속받아 구현</li>
<li>함수형 컴포넌트 : 함수형태로 구현</li>
</ol>
<p><img src="https://velog.velcdn.com/images/minni_/post/b20078a7-1f22-4f0c-a90e-5338f2c87433/image.png" alt="">
▶ 컴포넌트를 extends를 하면 윗 부분에 import구문이 자동으로 생성됨을 알 수 있다.
위 부분은  컴포넌트를 선언하는 내용이다.</p>
<ul>
<li>state와 prop(s)
React 컴포넌트는 두 종류의 데이터를 다룸</li>
</ul>
<ol>
<li>props(속성) : 부모 컴포넌트로 부터 전달되는 읽기 전용 데이터</li>
<li>state(상태) : 컴포넌트의 내부에서 관리되며 컴포넌트의 동작 및 UI 렌더링을 제어하는데 사용(내부 상태를 관리하는데 사용되는 데이터)</li>
</ol>
<pre><code>// 클래스형 컴포넌트
class Exam1 extends Component{ //컴포넌트의 선언부

[컴포넌트 정의 부분]

//필드

//생성자
constructor(prop) { 
        super(prop);
        this.state = { count : 0 };

// 메서드 (함수)
handleClick = () =&gt;{ //handleClick이라는 이름의 함수를 정의함
this.setState({count : this.state.count + 1});

// render 함수 (클래스형 컴포넌트에서 필수 구문)
    render(){
         return(
            &lt;div&gt;
                &lt;h1&gt;Count : {this.state.count}&lt;/h1&gt;
                &lt;button onclick={this.handleClick}&gt;증가&lt;/button&gt; 
            &lt;/div&gt;
         );
     }
  }
  export default Exam1; // 컴포넌트 내보내기</code></pre><ul>
<li><p>constructor(prop) 여기서 prop?
  부모에게 받은 속성 =&gt; super 생성자를 이용해 부모에게 전달하겠다는 내용</p>
</li>
<li><p>this.state = { count : 0 };  여기서 state ?
 컴포넌트의 내부 상태를 관리하는데 사용되는 데이터 
  =&gt; state 중에 count라는 이름을 가진 상태가 존재하는데 그 것에 초기값이 0이라는 뜻             (변수처럼 사용한다고 생각하면 됨)</p>
</li>
<li><p>간략히 정리하자면, count는 Exam1이라는 컴포넌트의 내부 상태 중 하나의 데이터이며, 초기값이 0으로 설정됨.</p>
</li>
</ul>
<h3 id="react에서-상태state와-변수variable의-차이점">React에서 상태(state)와 변수(variable)의 차이점</h3>
<p>공통점 : 데이터 저장과 관련
차이점 : 각기 다른 역할과 사용방식을 가짐.</p>
<ul>
<li><p>state (상태) : React 컴포넌트에서 데이터가 저장되는 곳. </p>
<pre><code>          상태 값이 변경될 때 마다 컴포넌트가 다시 렌더링 됨.</code></pre></li>
<li><p>variable (변수) : 컴포넌트 내에서 상태가 아닌 다른 데이터를 저장하기 위해 사용됨.</p>
<pre><code>             변수값이 변경되어도 컴포넌트는 다시 렌더링 되지 않음. </code></pre><p>  ex) let num = 0</p>
<pre><code>  num = 1 ; 

  ▶ 이 경우 변수는 값이 바뀌지 않는다. 렌더링이 되지 않는다.
  but, 상태는 감지되자마자 재랜더링이 된다.</code></pre></li>
<li><p>this.setState({count : this.state.count + 1});
▶ 이 컴포넌트의 상태(state) 중 count를 현재 상태값에서 +1한 값으로 상태를 다시 세팅(변경)</p>
</li>
<li><p>render() 함수
▶ 클래스형 컴포넌트에서 render 함수 안에 return 구문을 필수로 작성해야한다.
밑에 작성할  return에는 무엇을 렌더링 할지 작성하면 됨.</p>
</li>
<li><p>꼭 모든 함수를 작성한 후 구문을 다 빠져나와 해당함수를 기본적으로 내보낼 수 있도록 작성을 해줘야한다 export default Exam1; 이렇게!!
▶ 해당 Exam1.js 파일에서 기본적으로 내보내는 컴포넌트의 이름은 Exam1 이라는 뜻이고 컴포넌트를 내보낸다는 함수이다.</p>
</li>
</ul>
<p>이렇게 작성을 했다면 App.js에서 해당 js를 import하여 화면에 띄워주게 코드를 작성해주면 된다.</p>
<pre><code class="language-js">import logo from &#39;./logo.svg&#39;;
import &#39;./App.css&#39;;
import Exam1 from &quot;./exam/Exam1.js&quot;


function App() {
  return (
    &lt;div&gt;
      {/*여러가지 컴포넌트 불러다 사용!*/}
      {/* ctrl + / :jsx 주석 */}
      &lt;Exam1 /&gt;

    &lt;/div&gt;
  );
}

export default App;
</code></pre>
<p>결과는 바로 🎉 
<img src="https://velog.velcdn.com/images/minni_/post/84d36006-a222-4c16-9893-68b17359b45d/image.png" alt=""></p>
<p>▷ 현재 함수를 버튼을 적용시켜놓았기에 증가버튼을 누르면 count 옆에 숫자가 즉각적으로 반응하여 숫자가 증가하는 것을 볼 수 있다!</p>
<ol start="2">
<li>함수형 컴포넌트 만들기
: 함수 형 컴포넌트에서 상태를 사용하는 방법</li>
</ol>
<pre><code>function Exam2(){

    // 함수 형 컴포넌트에서 상태를 사용하는 방법
    const [name, setName] = useState(&quot;민경 :)&quot;);
    //name이라는 상태값에 초기값을 &quot;민경:)&quot;라고 지정한 것
    //useState 를 Hooks라고 부르는데 (기능모음) 그 중 상태값을 손쉽게 사용할 수 있게 만들어둔 것

    //setName :상태값을 변경해주는 함수!
    const handleClick = () =&gt; {
        setName(&quot;길동 :)&quot;);
    }
    //함수형 컴포넌트는 렌더링이 필요없음.
    return(// 함수형 컴포넌트는 render() 함수 제외하고 바로 return 작성하면 됨
        &lt;div&gt;
            &lt;h1&gt;Hello, {name}&lt;/h1&gt;
            &lt;button onClick={handleClick}&gt;이름 변경&lt;/button&gt;
        &lt;/div&gt;
    )
}
export default Exam2;</code></pre><p>위 함수형 컴포넌트도 작성이 다 되었다면 동일하게 App.js에 import추가해주면 된다.</p>
<pre><code>import logo from &#39;./logo.svg&#39;;
import &#39;./App.css&#39;;
import Exam1 from &quot;./exam/Exam1.js&quot;
import Exam2 from &#39;./exam/Exam2.js&#39;;

function App() {
  return (
    &lt;div&gt;
      {/*여러가지 컴포넌트 불러다 사용!*/}
      {/* ctrl + / :jsx 주석 */}
      &lt;Exam1 /&gt;
      &lt;Exam2/&gt;
    &lt;/div&gt;
  );
}

export default App;
</code></pre><p>결과는 🎉
<img src="https://velog.velcdn.com/images/minni_/post/b1c82425-cd42-4e4b-b779-374e902bc3ea/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/minni_/post/d771566f-ffef-487f-87f6-f9549346363f/image.png" alt=""></p>
<p>▷ 현재 이름변경 버튼에 함수를 적용해놓았고 새롭게 설정할 이름을 적어두어서 이름변경 버튼을 누르면 설정한 이름으로 변경되는 것을 볼 수 있다.</p>
<p>😎 리액트를 사용하니 js보다 훨씬 간편하고 좋다 익숙해지면 아주 좋을 것 같다!!!</p>
<p>※ 그리고 ! 최근에는 성능적, 간결성 등에서 함수형 컴포넌트를 많이 사용하고 있으니 참고!</p>
<hr>
**클래스형 컴포넌트와 함수형 컴포넌트의 장단점 구별**

<ol>
<li>클래스형 컴포넌트</li>
</ol>
<p>[ 장점 ]</p>
<p>1) 생명주기 메서드 제공 :</p>
<ul>
<li>componentDidMount, componentDidUpdate, domponentWillUnmoint ... 등의 생명주기 메서드를 사용할 수 있어서 컴포넌트의 생명주기 동안 특정 동작을 쉽게 구현할 수 있음.
but, 함수형 컴포넌트에서도 Hooks이 생기면서 생명주기 메서드를 쉽게 사용할 수 있게 되었음... ! 따라서 함수형 컴포넌트를 자주 사용하고 있다..!</li>
</ul>
<p>[ 단점 ]</p>
<p>1) 복잡성 </p>
<ul>
<li>문법이 복잡하고, this 키워드를 자주 사용해야 하므로 코드를 작성하고 이해하기 어려울 수 있음.
2) 코드길이 증가</li>
<li>함수형 컴포넌트에 비해 코드 길이가 길다
3) Hooks 도입 이후 감소된 사용</li>
</ul>
<ol start="2">
<li>함수형 컴포넌트 </li>
</ol>
<p>[ 장점 ]</p>
<p>1) 간결함</p>
<ul>
<li>코드 길이가 줄어들고, this 키워드를 사용할 필요가 없어서 이해하기가 쉬움.
2) Hooks 사용 가능</li>
<li>Hooks를 사용하여 함수형 컴포넌트에서도 상태관리와 생명주기 메서드와 유사한 기능을 구현할 수 있음.
3) 성능 최적화</li>
<li>메모리 사용이 더 적고 성능이 더 좋음</li>
</ul>
<p>[ 단점 ]</p>
<p>1) 생명주기 사용시 덜 직관적</p>
<ul>
<li>Hooks를 사용한 생명주기 관리가 클래스형 컴포넌트의 메서드보다 직관적이 않을 수 있음 (러닝커브 있을 수 있음)
2) 호환성이 떨어짐</li>
<li>레거시 코드 호환이 떨어짐. (기존 클래스형 컴포넌트와 호환이 어려울 수 있음)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React (1)]]></title>
            <link>https://velog.io/@minni_/React</link>
            <guid>https://velog.io/@minni_/React</guid>
            <pubDate>Mon, 03 Jun 2024 00:21:47 GMT</pubDate>
            <description><![CDATA[<p>리액트 REACT : 자바스크립트 라이브러리로, 사용자 인터페이스 (UI)를 구축하기 위해 사용(페이스북 제공)</p>
<p>특징</p>
<ol>
<li>컴포넌트 기반 구조</li>
</ol>
<ul>
<li>독립적이고, 재사용 가능한 코드 조각으로, 여러 컴포넌트를 조합하여 크고, 복잡한 사용자 인터페이스를 만들 수 있다.</li>
</ul>
<ol start="2">
<li>가상 DOM(Virtual DOM)</li>
</ol>
<ul>
<li>상태가 변경되면 실제 DOM에 변경을 적용하기 전에 가상DOM에 먼저 적용하고 나서 이를 실제 DOM과 변경DOM을 비교해서 필요한 부분만 업데이트 하는 방식 -&gt; 성능이 향상됨</li>
</ul>
<ol start="3">
<li>JSX(JavaScript Xml)
JSX는 자바스크립트와 HTML을 결합한 문법으로, UI를 정의할 때 직관적이고 읽기 쉽게 만들어 줌.
JSX는 브라우저가 이해할 수 있는 자바스크립트 코드로 변환을 해줌.</li>
</ol>
<pre><code>&lt;h1&gt;Hello, world!&lt;h1&gt; 이모양을 만든다면?

JS 
const h1= document.createElement(&quot;h1&quot;);
h1.innerText = &quot;Hello, world!&quot;;
body.append(h1);

JSX
const element = &lt;h1&gt;Hello, world!&lt;/h1&gt;;
return(
         {element}
)</code></pre><p>npm : node package manager (노드패키지 관리자)
yarn : npm의 성능을 보완하기 위해 나온 것 </p>
<p>  &lt;리액트 설치 방법&gt;
    node.js 설치하기 &gt; 원하는 곳에 폴더 생성 &gt; 폴더에서 마우스 우클릭 후 터미널 열기 &gt; 
    터미널에서 아래 내용 작성하면 됨</p>
<ul>
<li>설치가 잘되었는지 보는 방법
<img src="https://velog.velcdn.com/images/minni_/post/f9800a64-2b69-411a-961b-ae8d47e2906c/image.png" alt=""></li>
</ul>
<ul>
<li><p>yarn 설치하기
<img src="https://velog.velcdn.com/images/minni_/post/69850654-c854-482e-8d6e-47de78b19bfb/image.png" alt=""></p>
</li>
<li><p>프로젝트 생성하기
<img src="https://velog.velcdn.com/images/minni_/post/5b24cdb0-ac50-46e8-9f2e-a733ea72614a/image.png" alt=""></p>
</li>
</ul>
<p>Happy Hacking 문구가 뜨면 완료가 된 것임!</p>
<ul>
<li><p>vs코드에서 생성한 프로젝트 폴더 열기
<img src="https://velog.velcdn.com/images/minni_/post/753a5959-f88e-4f7f-9137-befea9c55f47/image.png" alt=""></p>
</li>
<li><p>vs코드에서 터미널 열고 터미널 git bash로 변경하기
<img src="https://velog.velcdn.com/images/minni_/post/8128a516-401d-4429-8b32-f2ab09d1b666/image.png" alt=""></p>
</li>
</ul>
<p>-변경 후 프로젝트 실행 시키기
<img src="https://velog.velcdn.com/images/minni_/post/555c7e70-6308-4905-be93-f0f45b803770/image.png" alt=""></p>
<p>** 리액트는 기본 포트번호를 3000을 사용하고 있음
<img src="https://velog.velcdn.com/images/minni_/post/e1db193d-45d2-4e5f-af2b-e2dc198febbc/image.png" alt=""></p>
<p>-&gt; 화면에 보여주고 싶은 모든 코드는 app.js에서 보여지고 있음.
    app.js return 구문에 작성되어있음을 알 수 있음</p>
<pre><code>![](https://velog.velcdn.com/images/minni_/post/c29338c6-f08b-4392-966e-9d8f82c0766f/image.png)</code></pre><p>▶ 앱 컴포넌트</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/5fc57c57-a820-4631-9811-d3ab680f6072/image.png" alt="">
▶ app.js에서 App이라는 함수를 가져온다는(불러온다는) 뜻
 <APP /> : 리액트에서 컴포넌트를 부르는 방식</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/71b9a6ec-8ddd-47ac-8385-bfa2756ccf76/image.png" alt="">
▶ root라는 id를 가진 dom의 요소를 root라고 부른다는 의미
root는 index.html파일 안에 있는  root라는 id를 가진 요소를 뜻한다.
<img src="https://velog.velcdn.com/images/minni_/post/44b400cc-35db-4bc8-9a48-d837e154425d/image.png" alt=""></p>
<pre><code class="language-node.js">const root = ReactDOM.createRoot(document.getElementById(&#39;root&#39;));
// &#39;root&#39;라는 id를 가진 DOM요소를 찾아 그것을 루트로 사용하도록 설정함 (public 폴더의 index.html에 존재)
root.render( // 루트를 통해 React 요소를 렌더링함. -&gt; 즉, &lt;App /&gt; 컴포넌트가 렌더링되어 DOM에 삽입됨.
  &lt;React.StrictMode&gt;
    &lt;App /&gt;
  &lt;/React.StrictMode&gt;

  // &lt;APP /&gt;만 있어도 되는데  &lt;React.StrictMode&gt; 태그로 감싸진 이유?
  // 성능향상을 위해 감싸져있는 것! 즉, StrictMode를 리액트에서 사용하겠다는 뜻(성능향상을 위해)
  // : 개발 중에 일부 문제를 검사하고 경고를 표시하여 개발자에게 앱의 잠재적인 문제를 알려줌.
);</code></pre>
<p><img src="https://velog.velcdn.com/images/minni_/post/1ac366ef-adc2-49d7-a126-8fadf1e2dfaf/image.png" alt="">
▶ 따라서 app안에 작성된 부분이 화면에 랜더링 되고 있다는 것을 한번 더 확인할 수 있음!</p>
<p>이 모든 내용이 즉, 아래 화면이다. 
<img src="https://velog.velcdn.com/images/minni_/post/3ddee256-1147-43ba-aa7e-f2c14f8627ce/image.png" alt=""></p>
<ul>
<li>jsx 에서 주석 =&gt; {/**/}   ctrl+/ ▶ (주석 자동완성)</li>
<li>터미널 열고 서버 끄고 켜는 방법
// 터미널 ctrl + shift + ` 로 열고
// 터미널에서 yarn start 서버 켜기
// 터미널에서 ctrl + c 서버 끄기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[오류 해결하기1]]></title>
            <link>https://velog.io/@minni_/%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B01</link>
            <guid>https://velog.io/@minni_/%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B01</guid>
            <pubDate>Mon, 08 Apr 2024 10:51:39 GMT</pubDate>
            <description><![CDATA[<p>TodoList를 생성하기 위해서 
todo에 제목, 내용을 작성한 후 제출하기를 누르면 
todoList에 todo가 추가되는 것을 생성하고 있었다!
분명히 분명히.. 아까는 오류없이 잘 되었지만
지금은 엄청난 오류가 발생했다.
음.. mapper.xml파일이 존재하지 않는다고 떠서 다시 살펴보려고 한다...
<img src="https://velog.velcdn.com/images/minni_/post/8efe0b05-0b0d-42d3-afe7-725b7638a4f1/image.png" alt="">
<img src="https://velog.velcdn.com/images/minni_/post/1df7425f-2670-4b64-ae4e-dee89455cef7/image.png" alt=""></p>
<p>status=500에러가 난다고 하는데 500에러는 일반적인 HTTP 상태 코드로 서버에서 문제가 발생하였으나 문제의 구체적인 내용을 표시할 수 없음을 의미한다고 한다. 지금 sql문에서 뭔가 인식을 못하는 느낌이다. 문제를 찾아보려고 한다.</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/1cf38dcb-4455-47ec-ba63-72d02292f8e9/image.png" alt=""></p>
<p>이게 근본적인 문제의 시작인 것 같다....</p>
<p>controller</p>
<pre><code class="language-java">@PostMapping(&quot;add&quot;)
    public String addTodo(
            @RequestParam(&quot;todoTitle&quot;) String todoTitle,
            @RequestParam(&quot;todoContent&quot;) String todoContent,
            RedirectAttributes ra 
            ) {

        int result = service.addTodo(todoTitle,todoContent);

        String message =null;

        if(result &gt; 0) message = &quot;할 일 추가 성공!&quot;;
        else        message =&quot;할 일 추가 실패! ㅜㅜ&quot;;


        ra.addFlashAttribute(&quot;message&quot;, message);

        return &quot;redirect:/&quot;;
    }```

``` java
    @Override
    public int addTodo(String todoTitle, String todoContent) {


        Todo todo = new Todo();
        todo.setTodoTitle(todoTitle);
        todo.setTodoContent(todoContent);

        return mapper.addTodo(todo);
    }</code></pre>
<pre><code class="language-xml"> &lt;insert id=&quot;addTodo&quot;  parameterType=&quot;Todo&quot;&gt;
          INSERT INTO TB_TODO
        VALUES(SEQ_TODO_NO.NEXTVAL, #{todoTitle}, #{todoContent}, DEFAULT,             DEFAULT )
  &lt;/insert&gt;</code></pre>
<p>[문제 해결!]</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/b7f89863-e1da-44ec-a6f6-d1bb601e4a8e/image.png" alt=""></p>
<p>이 엄청난 오류는 
그냥 내가 입력칸에 아무것도 입력하지 않고 제출하기를 눌러서.. 였다...................................ㅋㅋㅋㅋㅋㅋ
잘못된것이 없는데.. 왜 안되는거지 하다가 정말 허탈하게 오류가 해결되었다 :)</p>
<p>ㅋㅋㅋㅋ하하 재밌는 코딩세계~~</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/553ba2ac-c251-4393-98fd-8a98a5e506cb/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[VSC에 작성한 내용이 spring tool에 반영이 안되어 오류는 없지만 서버작동이 안되는 경우]]></title>
            <link>https://velog.io/@minni_/VSC%EC%97%90-%EC%9E%91%EC%84%B1%ED%95%9C-%EB%82%B4%EC%9A%A9%EC%9D%B4-spring-tool%EC%97%90-%EB%B0%98%EC%98%81%EC%9D%B4-%EC%95%88%EB%90%98%EC%96%B4-%EC%98%A4%EB%A5%98%EB%8A%94-%EC%97%86%EC%A7%80%EB%A7%8C-%EC%84%9C%EB%B2%84%EC%9E%91%EB%8F%99%EC%9D%B4-%EC%95%88%EB%90%98%EB%8A%94-%EA%B2%BD%EC%9A%B0</link>
            <guid>https://velog.io/@minni_/VSC%EC%97%90-%EC%9E%91%EC%84%B1%ED%95%9C-%EB%82%B4%EC%9A%A9%EC%9D%B4-spring-tool%EC%97%90-%EB%B0%98%EC%98%81%EC%9D%B4-%EC%95%88%EB%90%98%EC%96%B4-%EC%98%A4%EB%A5%98%EB%8A%94-%EC%97%86%EC%A7%80%EB%A7%8C-%EC%84%9C%EB%B2%84%EC%9E%91%EB%8F%99%EC%9D%B4-%EC%95%88%EB%90%98%EB%8A%94-%EA%B2%BD%EC%9A%B0</guid>
            <pubDate>Thu, 04 Apr 2024 10:28:45 GMT</pubDate>
            <description><![CDATA[<p>html 부분을 작성할 때 Spring tool을 사용하는 것 보다는 vsc를 사용하여 작성하는 것이
더 간편하여 그렇게 잘 작성하고 저장을 완료한 후 
잘 반영이 되었는지 확인을 해보려고 하는데?</p>
<p>뭔가 이상함을 감지했다...!</p>
<p>vsc에 작성한 html이 아무리 새로고침을 해도 반영이 안되고 있었고! 
배웠던 여러가지 설정은 다 잘 되어있는 상태였고 오류는 발생하고 있지 않는데 
계속해서 서버를 중단 하고 다시 실행해야만 
반영이 되는 상태였다........</p>
<p>물론 반복을 할 수는 있지만 반복되다보니 너~~무 불편했담🙄</p>
<p>그래서 SOS를 요청하여 알아낸 사실은 바로바로 </p>
<p><strong>Spring tool</strong>에 <strong>Build Automatically</strong>가 <strong>체크가 되어 있지 않아서</strong> 발생했던 것이었다!</p>
<p>원래는 자동으로 체크가 되어있다고 하던데...
가<del>~</del>끔 체크가 안되있는 경우가 발생하는데 그럴때마다 이러한 문제?가 발생한다고 한다!</p>
<p>혹시나 이러한 어려움을 겪고 있다면?
Build Automatically를 체크하면 문제를 해결할 수 있다😈</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/73caf9dd-06a9-4e96-81eb-27903672df68/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[이클립스 다이나믹 프로젝트 불러올 때 오류]]></title>
            <link>https://velog.io/@minni_/SERVER-ERROR</link>
            <guid>https://velog.io/@minni_/SERVER-ERROR</guid>
            <pubDate>Tue, 02 Apr 2024 10:14:39 GMT</pubDate>
            <description><![CDATA[<p>이클립스 다이나믹 프로젝트 불러올 때 오류!</p>
<p>학원에서 컴퓨터 자리를 변경하면서 이전에 만들어놨던 프로젝트를 깃에서 내려받아서 열려고 했더니
<img src="https://velog.velcdn.com/images/minni_/post/08b06fce-cc0b-4d31-b759-6f0ba26cb29d/image.png" alt=""></p>
<p>이렇게 오류가 발생하고 있었다..</p>
<p>코딩을 배우고 있지만.. 작은 오류에도 당황하는 나는 이것저것 해봤지만 문제를 찾지 못했고..!</p>
<p>결국 강사님께 여쭤보고서야 문제를 해결할 수 있었다.</p>
<p>바로 &quot;서버가 연결이 안되었기 때문&quot; 이다.</p>
<p>이전에 톰캣을 설치해서 설정을 해둔것에 대해서 프로젝트를 열었더니 새롭게 연 곳에서는 어떤 것을 읽어오려고 하는지에 대한 충돌?로 인해 오류가 발생한 것이다...</p>
<p>이럴 때 해결 방법은?</p>
<p>Package Explorer 에서 마우스 우 클릭 -&gt; Properties -&gt; Project Facets -&gt; Runtimes -&gt; Apache Tomcat 선택 한 후 Apply를 누르면 된다!</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/e8d26ef4-a898-44f1-8dba-b22dd7b80526/image.png" alt=""></p>
<p>기본적이고 간단한 것인데.. 해결을 못해버려서 다신 안잊어버릴 것 같다.. 🤦‍♀️ </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Server (개념)]]></title>
            <link>https://velog.io/@minni_/Server-%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@minni_/Server-%EA%B0%9C%EB%85%90</guid>
            <pubDate>Thu, 21 Mar 2024 01:22:15 GMT</pubDate>
            <description><![CDATA[<h1 id="🖥-웹-서비스">🖥 웹 서비스</h1>
<p>HTML, CSS, JS == 웹페이지</p>
<h2 id="서버-종류">서버 종류</h2>
<p>▫ <strong>정적 서비스 서버</strong> ▷ 웹서버(아파치 서버, 엔진엑스 NGINX)</p>
<p>▫ <strong>동적 서비스 서버</strong> ▷ WAS(Web Application Server) or 서블릿컨테이너</p>
<h3 id="❓-servlet">❓ Servlet</h3>
<p>: 사용자에게 보여지는 페이지(=웹 서비스)를 자바의 프로그래밍 기술로 표현하는(만드는) 것 Servlet!</p>
<p>📖 <strong>특징</strong></p>
<blockquote>
<p>▫ 클라이언트의 요청에 대해 동적으로 작동하는 웹 애플리케이션 컴포넌트.
▷클라이언트 요청에 대한 서버 응답 시 미리 만들어둔 화면(정적)이 아닌 요청을 받을 때 마다 알맞은 화면을 만들어(동적) 응답함.</p>
</blockquote>
<p>📖 <strong>Servlet 동작 방식</strong></p>
<p><img src="https://velog.velcdn.com/images/minni_/post/5751993e-5b1c-423e-9a7e-91b1604e72b2/image.png" alt=""></p>
<blockquote>
</blockquote>
<ol>
<li>사용자(클라이언트)가 URL(Uniform Resource Locator)을 클릭하면 HTTP Request(요청)를 Servlet Container로 전송</li>
<li>Http Request를 전송 받은 Servlet Container는 아래 두 객체를 생성</li>
</ol>
<p><strong>HttpServletRequest(요청 관련 내용이 저장된 객체),
HttpServletResponse(응답 관련 내용이 저장된 객체)</strong>
3. DD (배포서술자, Deployment Descriptor) = <strong>web.xml</strong>은 사용자가 요청한 URL을 분석하여 어떤 서블릿 클래스에 요청 내용을 전달할지 찾음
4. 해당 서블릿에서 init() 메소드를 먼저 호출한 후 service() 메소드를 호출하여 클라이언트로부터 전송 받은 방식인 GET, POST 여부에 따라 해당 메소드(doXXX()) 를 호출함.
5. doGet() / doPost() 메소드는 동적 페이지를 생성 후 <strong>HttpServletResponse</strong>객체에 응답을 보냄
6. 응답 종료 시 <strong>HttpServletRequest, HttpServletResponse</strong> 객체 소멸</p>
<p><strong>클라이언트가 서버로 요청을 방법에는 Get / Post 방식이 있다!</strong></p>
<h3 id="📤-get방식">📤 GET방식</h3>
<p><strong>:(데이터를) 가져오다, 얻어오다</strong></p>
<blockquote>
<p>▫ URL에 변수(데이터)를 포함시켜 요청
보안 유지를 안 하기 때문에 로그인 같은 경우는 get방식으로 하면 부적합..!
why? 주소창에 사용자의 값이 다 노출되기 때문에! 보안에는 취약하다 😥 그래서 <strong>단순히 데이터를 요청</strong>할 때만 사용하는 것이 좋음 == <strong>페이지 이동</strong>)
<br>
▫ 👀 만약 이와 같은 데이터를 요청하는 경우에는 <strong>HTTP Header</strong>에 포함하여 전송하면,
GET방식에서 바디는 보통 <strong>빈 상태로 전송</strong> 되며 헤더의 내용 중 Body의 데이터를 설명하는 Content-type헤더필드도 들어가지 않음
<br>
▫ 전송하는 <strong>길이 제한</strong>(보내는 길이가 너무 길면 초과데이터는 절단됨)
<br>
▫ <strong>캐싱 가능 *<em>(ex. 즐겨찾기, 북마크)
(한번 접근 후, 또 요청할 시 빠르게 접근하기 위해 데이터를 저장시켜 놓는 것)
<br>
🙋‍♀️ *</em>여기서 잠깐?</strong>
url+/+?+<code>변수명 +변수명+ 변수값</code> 에서 <code>?</code>뒤에 붙는 것을 queryString라고 한다.</p>
</blockquote>
<h3 id="📤-post방식">📤 POST방식</h3>
<p><strong>: (데이터를) 붙이다</strong></p>
<blockquote>
<p>▫ 데이터를 서버로 제출하여 추가 또는 수정하기 위해 데이터를 전송하는 방식인데,서버에서 데이터를 보낼때 중요한 내용들을 보내는 경우 사용하는 방식!(로그인과 같은 것들! 중요정보들)
<br>
▫ <strong>URL에 변수(데이터)를 노출하지 않고</strong> 요청 데이터를 <strong>HTTP Body</strong>에 포함하여 전송
<br>
▫ 헤더필드 중 Body의 데이터를 설명하는 Content-Type이라는 헤더필드가 들어가고
어떤 데이터 타입인지 명시해주어야 함
<br>
▫ 전송하는 <strong>길이 제한이 없음</strong>.
▷ Body에 데이터가 들어가기 때문에 길이에 제한이 없지만, 최대 요청을 받는 시간(Time Out)이 존재해서 페이지 요청, 기다리는 시간 존재
<br>
▫ <strong>캐싱할 수 없음.</strong>
▷ <strong>URL에 데이터가 노출 되지 않으므로</strong> 즐겨찾기나 캐싱 불가능(중요정보들이기 때문!)
하지만 쿼리스트링(문자열)데이터, 라디오 버튼, 텍스트 박스와 같은 객체들의 값도 전송 가능
<br>
👩‍💻 post방식은 json타입으로 클라이언트가 서버로 보낸다 (ex { &quot;name1&quot;:&quot;value1&quot; &quot;name2&quot;: &quot;value2&quot;... } ▷ MAP과 비슷한 형태)</p>
</blockquote>
<hr>
<h3 id="❓-was">❓ WAS</h3>
<p>: 웹서버로 부터 오는 동적인 요청을 처리하는 서버  (동적서비스 서버이지만 정적서비스도 함께 처리할 수 있음 == 아파치톰캣) (==&gt;** Tomcat 서비스**)</p>
<hr>
<p><strong>아파치 톰캣 사용 전 다운로드 방법!</strong>
[[ <a href="http://tomcat.apache.org/">http://tomcat.apache.org/</a> ]]</p>
<h3 id="❓-아파치-톰캣-apache-tomcat">❓ 아파치 톰캣 (Apache Tomcat)</h3>
<blockquote>
<p>Java로 웹 어플리케이션을 만들기 위해 JSP(Java Server Page)나 서블릿 (Servlet)을 사용해 서버와 통신하기 위해서는 서버가 구축이 되어 있어하는데 이때, 사용하는 서버가 아파치 톰캣이다.
🪄즉! Tomcat이 처리할 수 없는 정적 페이지 처리를 위해서 아파치의 일부 기능을 가져와 함께 제공하는 서버를 말한다.</p>
</blockquote>
<h4 id="👩💻한눈에-보기-쉽게-정리-하자면"><strong>👩‍💻한눈에 보기 쉽게 정리 하자면!</strong></h4>
<blockquote>
</blockquote>
<h3 id="❓tomcat">❓Tomcat</h3>
<p>: 서블릿 컨테이너의 대표적인 서비스로 서블릿이 작동하는 환경을 제공해주는 서비스로 동적인 서비스를 처리해준다. (== WAS, 서블릿 컨테이너)
<br></p>
<h3 id="❓was">❓WAS</h3>
<p>: 웹서버로부터 오는 동적인 요청을 처리하는 서버로 컨테이너와 웹서버를 모두 포함하고 있다. 
WAS는 이용시 동적, 정적 서비스 ** 모두!!** 처리가 가능하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[XML (파일 생성하기)]]></title>
            <link>https://velog.io/@minni_/XML-%ED%8C%8C%EC%9D%BC-%EC%83%9D%EC%84%B1%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@minni_/XML-%ED%8C%8C%EC%9D%BC-%EC%83%9D%EC%84%B1%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 19 Mar 2024 08:58:37 GMT</pubDate>
            <description><![CDATA[<h2 id="📘-xmlextensible-markup-language">📘 XML(eXtensible Markup Language)</h2>
<blockquote>
<p><strong>단순화된 데이터 기술 형식</strong></p>
</blockquote>
<ul>
<li>XML에 저장되는 데이터 형식은 모두  Key : Value 형식이고, (HTML과 같이..?!)
Key , Value 모두 String(문자열) 형식이다.</li>
</ul>
<p>XML 파일을 읽고, 쓰기 위한 IO 관련 클래스 필요한데..! <strong>Properties</strong> 컬렉션 객체가 필요하다.</p>
<h3 id="📖-properties-컬렉션-객체">📖 Properties 컬렉션 객체</h3>
<blockquote>
<ul>
<li>Map 후손 클래스 </li>
</ul>
</blockquote>
<ul>
<li>Key, Value 모두 String(문자열)</li>
<li>XML 파일을 읽고, 쓰는데 특화된 메서드 제공</li>
</ul>
<p>👩‍💻 <strong>그렇다면 xml 파일을 생성해보자!</strong></p>
<pre><code class="language-java">try {
    Scanner sc = new Scanner(System.in);

    // ✔ Properties 객체 생성
            Properties prop = new Properties();

            System.out.print(&quot;생성할 파일 이름 : &quot;);
            String fileName = sc.next();

    // ✔ FileOutputStream 생성 
            FileOutputStream fos = new FileOutputStream(fileName + &quot;.xml&quot;);


    // ✔ Properties 객체를 이용해서 XML 파일 생성
            prop.storeToXML(fos, &quot;.xml file!!!&quot;);

     System.out.println(fileName+ &quot;.xml 파일 생성 완료&quot;);

}catch (Exception e) {
            e.printStackTrace();
}</code></pre>
<p>➡ <strong>XML file 생성 시 Exception이 발생하기에 try~catch문 안에 작성해주면 된다!</strong> 🙋‍♀️    </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JDBCTemplate]]></title>
            <link>https://velog.io/@minni_/JDBC2</link>
            <guid>https://velog.io/@minni_/JDBC2</guid>
            <pubDate>Tue, 19 Mar 2024 08:45:03 GMT</pubDate>
            <description><![CDATA[<p>현재 배운 것을 바탕으로 RUN ▶ VIEW ▶ SERVICE ▶ DAO 순서로 작성해보려고 한다. 
더불어, XMLFILE을 생성하는 Class를 만들어서 .xml 파일을 만들고 sql내용을 작성한 후 이를 연결하여 실행해보려고 한다. </p>
<p>그 전에 개념을 먼저 알아본 후 <strong>JDBCTemplate 클래스</strong>를 만들어보자!👩‍🏫</p>
<h1 id="jdbctemplate">JDBCTemplate?</h1>
<p>DB 연결 (Connection 생성)+ 자동 커밋 off , JDBC 객체 자원 반환(close)
과 같은 트랜잭션 제어를 JDBC에서 반복 사용되는 코드를 모아둔 클래스를 말한다.</p>
<p>[특징]
모든 필드, 메서드가 <code>static</code> 이다.
➡ 어디서든지 클래스명.필드명 / 클래스명.메서드명 호출 가능하고, 
➡ 별도 객체 생성하지 않아도 된다.👍</p>
<hr>
<pre><code class="language-java">private static Connection conn = null;

    📑 DB 연결 정보를 담고있는 Connection 객체 생성 및 반환 메서드
     // @return conn

    public static Connection getConnection() {

        try {
            // ✔ 현재 커넥션 객체가 없을 경우 ▷ 새 커넥션 객체 생성하라는 조건문
            if(conn == null || conn.isClosed()) {
                // conn.isClosed() : 커넥션이 close 상태면 true 반환

                Properties prop = new Properties();
                // Map&lt;String,String&gt; 형태의 객체, XML 입출력 특화

                // ✔ driver.xml 파일 읽어오기
                prop.loadFromXML(new FileInputStream(&quot;driver.xml&quot;));
                //▷ xml 파일에 작성된 내용이 Properties 객체에 모두 저장됨.

                // ✔ XML에서 읽어온 값을 모두 변수에 저장하기
                String driver = prop.getProperty(&quot;driver&quot;);
                String url =prop.getProperty(&quot;url&quot;);
                String user = prop.getProperty(&quot;user&quot;);
                String password = prop.getProperty(&quot;password&quot;);

                // ✔ 커넥션 생성하기
                Class.forName(driver); //Oracle JDBC Driver 객체 메모리 로드

                // DriverManager 통해 Connection 객체 생성하기
                conn = DriverManager.getConnection(url,user,password);

                // + 자동 커밋 비활성화하기
                conn.setAutoCommit(false);

            }
        } catch (Exception e) {
            System.out.println(&quot;[Connection 생성 중 예외 발생]&quot;);
            e.printStackTrace();
        }

        return conn; //▷ 생성 및 설정된 Connection 객체 반환 하기
    }
</code></pre>
<pre><code class="language-java">    📑 Connection 객체를 자원 반환 메서드
     // @param conn

    public static void close(Connection conn) {

        try {
       /*
       ✔ 전달 받은 conn이 참조하는 Connection 객체가 있고, 
         그 Connection 객체가 close 상태가 아니라면 자원반환하라는 조건문
       */
            if(conn != null &amp;&amp; !conn.isClosed()) conn.close(); //▷ 자원반환!

        } catch (Exception e) {
            e.printStackTrace();
        }
    }</code></pre>
<pre><code class="language-java">    📑 Statement(부모), PreparedStatement(자식) 객체 자원 반환 메서드
    // @param stmt

    public static void close(Statement stmt) {

        try {
            if(stmt != null &amp;&amp; !stmt.isClosed()) stmt.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
</code></pre>
<pre><code class="language-java">    📑 ResultSet 객체 자원 반환 메서드
     // @param rs

    public static void close(ResultSet rs) {

        try {
            if(rs != null &amp;&amp; !rs.isClosed()) rs.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }</code></pre>
<pre><code class="language-java">    📑 트랜잭션 commit 메서드
     // @param conn

    public static void commit(Connection conn) {

        try {
            if(conn != null &amp;&amp; !conn.isClosed()) conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }</code></pre>
<pre><code class="language-java">    📑 트랜잭션 rollback 메서드
     // @param conn

    public static void rollback(Connection conn) {
        try {
            if(conn != null &amp;&amp; !conn.isClosed()) conn.rollback();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[JDBC ?]]></title>
            <link>https://velog.io/@minni_/JDBC-1</link>
            <guid>https://velog.io/@minni_/JDBC-1</guid>
            <pubDate>Mon, 18 Mar 2024 08:45:05 GMT</pubDate>
            <description><![CDATA[<h1 id="jdbcjava-database-connectivity">JDBC(Java DataBase Connectivity)</h1>
<blockquote>
<p>Java에서 DB에 연결할 수 있게 해주는 Java Programming API(Java에 기본 내장된 인터페이스)
➡ <strong>JDBC는 java.sql 패키지에서 제공</strong></p>
</blockquote>
<h4 id="💡-jdbc를-이용한-어플리케이션-만들때-필요한-것">💡 JDBC를 이용한 어플리케이션 만들때 필요한 것</h4>
<blockquote>
<ol>
<li>Java의 JDBC 관련 인터페이스</li>
<li>DBMS (Oracle)</li>
<li>Oracle에서 Java와 연결할 때 사용할 JDBC를 상속받아 구현할 클래스 모음(ojdbc10.jar 라이브러리)</li>
</ol>
</blockquote>
<p><strong>그렇다면,</strong> JDBC를 이용하기 위해 단계별로 해야하는 것들에 대해서 알아보자!</p>
<hr>
<h3 id="📕-1단계">📕 1단계</h3>
<blockquote>
<p>JDBC 객체 참조 변수를 선언해야한다(java.sql 패키지의 인터페이스로 import 해야함!)</p>
</blockquote>
<p><strong>📑 Connection
DB 연결 정보를 담을 객체</strong></p>
<pre><code class="language-java">Connection conn = null;</code></pre>
<br>

<p><strong>🤷‍♀️ 여기서 잠깐</strong> ❓
** DB연결 정보는**  DBMS 타입, 이름, IP, Port, 계정명, 비밀번호 저장을 말한다.</p>
<p>DBeaver의 계정 접속 방법과 유사하다고 할 수 있으며 이 연결 정보는 <strong>Java와 DB 사이를 연결해주는 통로 역할</strong>을 할 것이다.</p>
<br>

<p>📑 <strong>Statement</strong>
Connection을 통해 <strong>SQL문을 DB에 전달하여 실행하고 생성된 결과</strong> (ResultSet, 성공한 행의 개수)<strong>를 반환(Java)하는데 사용되는 객체</strong></p>
<pre><code class="language-java">Statement stmt = null;</code></pre>
<br>

<p>📑 <strong>ResultSet</strong>
SELECT 질의 성공 시 반환되는데, 조회 결과 집합을 나타내는 객체</p>
<pre><code class="language-java">ResultSet rs = null;</code></pre>
<h3 id="📕-2단계">📕 2단계</h3>
<blockquote>
<p>참조변수에 알맞은 객체를 대입한다.</p>
</blockquote>
<h4 id="1-db-연결에-필요한-oracle-jdbc-driver-메모리에-로드하기">1. DB 연결에 필요한 Oracle JDBC Driver 메모리에 로드하기</h4>
<p>◾ 런타임 시점에 해당 경로의 클래스를 동적으로 로드함</p>
<pre><code class="language-java">Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);</code></pre>
<p>▷ () 안에 작성된 클래스의 객체를 반환한다.
▶ 메모리에 객체가 생성되어지고 JDBC 필요 시 알아서 참조하여 사용되기에 생략해도 자동으로 메모리 로드가 진행된다!** BUT,** 명시적으로 작성하는 걸 권장하기에 적어주면 좋다<strong>!</strong></p>
<h4 id="2-연결정보를-담은-connection을-생성하기">2. 연결정보를 담은 Connection을 생성하기</h4>
<p>◾ DriverManager 객체를 이용해서 Connection 객체를 만들어 이용            </p>
<pre><code class="language-java">String type = &quot;jdbc:oracle:thin:@&quot;; ▷▶ JDBC 드라이버 종류
String ip = &quot;localhost&quot;; ▷▶ DB 서버 컴퓨터 IP // == 127.0.0.1 (loop back ip)
String port = &quot;:1521&quot;; ▷▶ 포트번호 // 1521 (기본값)
String sid =&quot;:XE&quot;; ▷▶  DB 이름 // url == jdbc:oracle:thin:@localhost:1521:XE
String user = &quot;kh_lmk&quot;; ▷▶ 사용자계정
String pw = &quot;kh1234&quot;; ▷▶  비밀번호</code></pre>
<p>** ❗ 단점** : 개인정보가 들어간 데이터를 넣기 때문에 보안상의 문제가 있으니 주의가 필요함 🤦‍♀️</p>
<p><strong>객체를 만든 후 DriverManager에 전달하는데... 여기서?</strong>
 <strong>DriverManager란 ❓</strong> 메모리에 로드된 JDBC 드라이버를 이용해서 Connection 객체를 만드는 역할을 말한다.</p>
<pre><code class="language-java">conn = DriverManager.getConnection(type+ip+port+sid,user,pw);
 url == jdbc:oracle:thin:@localhost:1521:XE</code></pre>
<h4 id="3-sql-작성하기">3. SQL 작성하기</h4>
<p>📣 <strong>주의 사항</strong> 
** JAVA에서 작성되는 SQL은 마지막에 <code>;</code> 을 찍으면 안된다!**</p>
<pre><code class="language-java">❌ String sql =&quot;SELECT EMP_ID, EMP_NAME, SALARY, HIRE_DATE FROM EMPLOYEE;&quot;;
</code></pre>
<pre><code class="language-java">⭕ String sql =&quot;SELECT EMP_ID, EMP_NAME, SALARY, HIRE_DATE FROM EMPLOYEE&quot;;</code></pre>
<h4 id="4-statement-객체-생성하기">4. Statement 객체 생성하기</h4>
<p>◾ Connection 객체를 통해서 생성</p>
<pre><code class="language-java">stmt = conn.createStatement();</code></pre>
<h4 id="5-생성된-statement객체에-sql-을-적재하여-실행한-후-결과를-반환-받아와서-rs-변수에-저장하기">5. 생성된 Statement객체에 sql 을 적재하여 실행한 후 결과를 반환 받아와서 rs 변수에 저장하기</h4>
<pre><code class="language-java">rs =stmt.executeQuery(sql);
//▷▶ executeQuery() : SELECT문 수행 메서드, ResultSet 반환</code></pre>
<h3 id="📕-3단계">📕 3단계</h3>
<blockquote>
<p>SQL을 수행해서 반환 받은 결과 (ResultSet)를 한 행씩 접근해서 컬럼값 얻어오기</p>
</blockquote>
<pre><code class="language-java">while(rs.next()) {
✔rs.next() : rs가 참조하고 있는 ResultSet 객체의 첫 번째 컬럼부터 순서대로 한행씩 이동하며 다음 행이 있을 경우, 
true, 없으면 false 반환!

◾ [작성방법] : rs.get자료형(&quot;컬럼명&quot;)

    String empId = rs.getString(&quot;EMP_ID&quot;); 
    //▶ &quot;200&quot;, ➡ 현재 행의 &quot;EMP_ID&quot; 문자열 컬럼의 값을 얻어옴

    String empName = rs.getString(&quot;EMP_NAME&quot;); //▶ &quot;선동일&quot;

    int salary = rs.getInt(&quot;SALARY&quot;); //▶ 8,000,000

    //[java.sql.Date]
    Date hireDate = rs.getDate(&quot;HIRE_DATE&quot;); //▶ YYYY-MM-DD 1990-02-06

    System.out.printf(&quot;사번 : %s / 이름 : %s / 급여 : %d / 입사일 : %s \n&quot;,
                        empId, empName, salary, hireDate);

    //👀 java.sql.Date의 toString()은 yyyy-mm-dd 형식으로 오버라이딩 되어있음.
}</code></pre>
<h3 id="📕-4단계">📕 4단계</h3>
<blockquote>
<p>사용한 JDBC 객체 자원 반환하기! <code>(close())</code></p>
</blockquote>
<p>▷ Connection, Statement, ResultSet 으로 실행했다면,
close할 때는 생성된 <strong>역순</strong>(ResultSet➡Statement➡Connection)으로 닫는 것을 <strong>권장</strong>함.</p>
<pre><code class="language-java">📣 finally 안 try~catch문 중 try부분에 작성!            

if(rs!= null) rs.close();
if(stmt!= null) stmt.close();
if(conn!= null) conn.close(); //▶ 각자 독립적인 객체들이기에 각각 다 닫아줘야 함!</code></pre>
<h2 id="👩💻-연습문제-time">👩‍💻 연습문제 time!</h2>
<pre><code class="language-java">
/* 
직급명, 급여를 입력받아 해당 직급에서 입력 받은 급여보다 많이 받는 사원의 이름, 직급명, 급여, 연봉을 조회하여 출력
✔ 단, 조회결과가 없으면 &quot;조회 결과 없음&quot; 출력!
✔조회 결과가 있으면 아래와 같이 출력!
[입력내용]
직급명 입력 : 부사장
급여 입력 : 5000000
[출력내용]
송종기 / 부사장 / 6000000 /72000000
노옹철 / 부사장 /3700000/44400000 
*/

        // Employee (empName, jobName, salary, annualIncome)


        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        Scanner sc = new Scanner(System.in);

        try {

            System.out.print(&quot;직급명 입력 : &quot;);
            String input1 = sc.next();

            System.out.print(&quot;급여 입력 : &quot;);
            int input2 = sc.nextInt();

            Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);

            String url = &quot;jdbc:oracle:thin:@localhost:1521:XE&quot;;
            String user = &quot;kh_lmk&quot;;
            String pw = &quot;kh1234&quot;;
            conn = DriverManager.getConnection(url,user,pw);

            String sql = &quot;SELECT EMP_NAME, JOB_NAME, SALARY, SALARY*12 AS ANNUALINCOME&quot;
                    + &quot; FROM EMPLOYEE&quot;
                    + &quot; JOIN JOB USING(JOB_CODE)&quot;
                    + &quot; WHERE JOB_NAME = &#39;&quot; + input1 +&quot;&#39;&quot;
                    + &quot; AND SALARY &gt; &quot;+input2;

            stmt = conn.createStatement();
            rs = stmt.executeQuery(sql);

            List&lt;Employee&gt; list = new ArrayList&lt;Employee&gt;();

            while(rs.next()) {
                String empName = rs.getString(&quot;EMP_NAME&quot;);
                String jobName = rs.getString(&quot;JOB_NAME&quot;);
                long salary = rs.getInt(&quot;SALARY&quot;);
                long annualIncome = rs.getInt(&quot;ANNUALINCOME&quot;);

                list.add(new Employee(empName, jobName, salary, annualIncome));

            }

            if(list.isEmpty()) {
                System.out.println(&quot;조회 결과 없음&quot;);
            }else {
                for(Employee employee : list) {
                    System.out.println(employee);
                }
            }


        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(rs != null) rs.close();
                if(stmt != null) rs.close();
                if(conn != null) rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }</code></pre>
<pre><code class="language-java">
//입사일을 입력(&quot;2000-01-01&quot;) 받아 입력 받은 값 보다 먼저 입사한 사람의 이름, 입사일, 성별(M,F) 조회

        Scanner sc = new Scanner(System.in);

        Connection conn = null;
        Statement stmt =null;
        ResultSet rs = null;

        try {

            System.out.println(&quot;입사일 입력(YYYY-MM-DD) : &quot;);
            String input = sc.next();

            Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);

            String url = &quot;jdbc:oracle:thin:@localhost:1521:XE&quot;;
            String user = &quot;kh_lmk&quot;;
            String pw = &quot;kh1234&quot;;
            conn = DriverManager.getConnection(url,user,pw);


            String sql = &quot;SELECT EMP_NAME 이름 , TO_CHAR(HIRE_DATE,&#39;YYYY\&quot;년\&quot; MM\&quot;월\&quot; DD\&quot;일\&quot;&#39;)  입사일,&quot;
                    + &quot; DECODE(SUBSTR(EMP_NO,8,1),1,&#39;M&#39;,2,&#39;F&#39;) AS 성별&quot;
                    + &quot; FROM EMPLOYEE&quot;
                    + &quot; WHERE  HIRE_DATE &lt;  TO_DATE(&#39;&quot;+input+&quot;&#39;)&quot;;

        stmt = conn.createStatement();
        rs=stmt.executeQuery(sql);

        List&lt;Employee&gt; list = new ArrayList&lt;Employee&gt;();

        while(rs.next()) {

            Employee emp = new Employee();

            emp.setEmpName(rs.getString(&quot;이름&quot;)); //조회 시 컬럼명이 &quot;이름&quot;
            emp.setHireDate(rs.getString(&quot;입사일&quot;)); //조회 시 컬럼명이 &quot;입사일&quot;
            emp.setGender(rs.getString(&quot;성별&quot;).charAt(0)); //조회 시 컬럼명이 &quot;성별&quot; / char 형태이기에 ! charaAt사용
            //JaVA의 char : 문자 1개의 의미
            //DB의 char : 고정길이 문자열 (== String)

            list.add(emp);
        }

        // 조회결과가 없는 경우
        if(list.isEmpty()) {
            System.out.println(&quot;조회결과 없음&quot;);
        }else {

            for(int i =0; i&lt;list.size();i++) {
                System.out.printf(&quot;%02d) %s / %s / %c\n&quot;,i+1,list.get(i).getEmpName(), list.get(i).getHireDate(),list.get(i).getGender()   );

            }
        }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(rs !=null) rs.close();
                if(stmt != null) stmt.close();
                if(conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[DCL]]></title>
            <link>https://velog.io/@minni_/DCL</link>
            <guid>https://velog.io/@minni_/DCL</guid>
            <pubDate>Tue, 12 Mar 2024 08:04:51 GMT</pubDate>
            <description><![CDATA[<h1 id="📘-dcldata-control-language">📘 DCL(Data Control Language)</h1>
<blockquote>
<p><strong>데이터를 다루기 위한 권한을 다루는 언어</strong></p>
</blockquote>
<ul>
<li>계정에 DB, DB 객체에 대한 접근 권한을 부여(GRANT)하고 회수(REVOKE)하는 언어</li>
</ul>
<h3 id="📖-권한의-종류">📖 권한의 종류</h3>
<p> <strong>1) 시스템 권한</strong> : DB접속, 객체 생성 권한</p>
<blockquote>
<ul>
<li>*<em>CRETAE SESSION *</em>  : 데이터베이스 접속 권한</li>
</ul>
</blockquote>
<ul>
<li><strong>CREATE TABLE</strong>     : 테이블 생성 권한</li>
<li><strong>CREATE VIEW</strong>      : 뷰 생성 권한</li>
<li><strong>CREATE SEQUENCE</strong>  : 시퀀스 생성 권한</li>
<li><strong>CREATE PROCEDURE</strong> : 함수(프로시져) 생성 권한</li>
<li><strong>CREATE USER</strong>      : 사용자(계정) 생성 권한</li>
<li><strong>DROP USER</strong>        : 사용자(계정) 삭제 권한</li>
<li><strong>DROP ANY TABLE</strong>   : 임의 테이블 삭제 권한</li>
</ul>
<p>** 2) 객체 권한 : 특정 객체를 조작할 수 있는 권한**</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/aa2c6db3-5f39-4b5f-89df-aa75b5ea624d/image.png" alt=""></p>
<h3 id="📖-user---계정사용자">📖 USER - 계정(사용자)</h3>
<blockquote>
<p>✔ <strong>관리자 계정</strong> 
◾ 데이터베이스의 생성과 관리를 담당하는 계정. 
◾ 모든 권한과 책임을 가지는 계정.
ex) sys(최고관리자), system(sys에서 권한 몇개 제외된 관리자)
<br>
✔ <strong>사용자 계정</strong>
◾ 데이터베이스에 대하여 질의, 갱신, 보고서 작성 등의 작업을 수행할 수 있는 계정으로 업무에 필요한 최소한의 권한만을 가지는 것을 원칙으로 한다.
ex) kh_bdh계정(각자 이니셜 계정), workbook 등</p>
</blockquote>
<p><code>GRANT RESOURCE, CONNECT TO kh_lmk;</code></p>
<p>✔ <strong>롤 (ROLE)</strong>
: 다수 사용자와 다양한 권한을 효율적으로 관리하기 위하여 서로 관련된 권한을 그룹화한 개념(권한의 묶음)</p>
<pre><code class="language-sql">SELECT * FROM ROLE_SYS_PRIVS
WHERE ROLE = &#39;RESOURCE&#39;;</code></pre>
<p>ROLE_SYS_PRIVS❓
오라클 DB에서 시스템 권한을 가진 역할을 나타내는 데이터 딕셔너리 뷰를 말한다.</p>
<p><img src="https://velog.velcdn.com/images/minni_/post/9fe606e4-e528-468e-bdb4-961b44b2c69a/image.png" alt=""></p>
<pre><code class="language-sql">SELECT * FROM ROLE_SYS_PRIVS
WHERE ROLE = &#39;CONNECT&#39;;</code></pre>
<p><img src="https://velog.velcdn.com/images/minni_/post/fa702e70-aba3-431a-91d1-2764ee2cdcf9/image.png" alt=""></p>
<p>➡ CREATE 트리거, 시퀀스, 테이블 등 8가지 권한이 부여되어있음</p>
<hr>
<p>👩‍💻 <strong>계정 생성 방법에 대해서 알아보자!</strong></p>
<blockquote>
<h4 id="✔-1-sys사용자-계정-생성">✔ 1. (SYS)사용자 계정 생성</h4>
<p><code>ALTER SESSION SET &quot;_ORACLE_SCRIPT&quot; = TRUE;</code>
▶ 예전 SQL 방식 허용 (계정명을 간단히 작성 가능)</p>
</blockquote>
<pre><code class="language-sql">📑 작성법
CREATE USER 사용자명 IDENTIFIED BY 비밀번호;
CREATE USER lmk_sample IDENTIFIED BY sample1234; </code></pre>
<h4 id="✔-2-새-연결-추가-❗❗-오류발생">✔ 2. 새 연결 추가 (❗❗ 오류발생)</h4>
<p>🤷‍♀️ ORA-01045: 사용자 LMK_SAMPLE는 CREATE SESSION 권한을 가지고있지 않음로그온이 거절되었습니다 
❌오류 발생이유? 접속 권한 (CREATE SESSION) 없어서 !</p>
<h4 id="✔-3-접속-권한-부여">✔ 3. 접속 권한 부여</h4>
<pre><code class="language-sql">📑 권한 부여 작성법
GRANT CREATE SESSION, 권한, 권한 ... TO 사용자명;
GRANT CREATE SESSION TO lmk_sample;</code></pre>
<h4 id="✔-4-다시-연결-추가-📣-성공">✔ 4. 다시 연결 추가 📣 <strong>성공</strong></h4>
<h4 id="✔-5-sample테이블-생성">✔ 5. (sample)테이블 생성</h4>
<pre><code class="language-sql">CREATE TABLE TB_TEST(
    PK_COL NUMBER PRIMARY KEY,
    CONTENT VARCHAR2(100)
);
 ORA-01031: 권한이 불충분합니다
▶ CREATE TABLE : 테이블 생성 권한 
(+) 데이터를 저장할 수 있는 공간(TABLESPACE) 할당</code></pre>
<h4 id="✔-6-sys-테이블-생성권한--tablespace-할당">✔ 6. (SYS) 테이블 생성권한 + TABLESPACE 할당</h4>
<pre><code class="language-sql"> GRANT CREATE TABLE TO lmk_sample;
ALTER USER lmk_sample DEFAULT TABLESPACE 
SYSTEM QUOTA UNLIMITED ON SYSTEM;</code></pre>
<p>▶ sample 계정의 설정을 변경하여 해당 사용자가 system 테이블 스페이스에서 무제한으로 공간을 사용할 수 있도록 변경함.</p>
<h4 id="✔-7-sample-다시-테이블-생성">✔ 7. (sample) 다시 테이블 생성</h4>
<pre><code class="language-sql">CREATE TABLE TB_TEST(
    PK_COL NUMBER PRIMARY KEY,
    CONTENT VARCHAR2(100)
);</code></pre>
<p>◾ (SYS)sample 계정에 CONNECT, RESOURCE 부여</p>
<pre><code class="language-sql">GRANT CONNECT, RESOURCE TO lmk_sample;</code></pre>
<p>💡 여기서 잠깐!
<strong>CONNECT</strong> ❓ DB 접속 관련 권한을 묶어둔 ROLE
*<em>RESOURCE *</em> ❓ DB 사용을 위한 기본 객체 생성 권한을 묶어둔 ROLE</p>
<hr>
<h3 id="📖-객체권한">📖 객체권한</h3>
<p><strong>사용자 계정끼리</strong>(kh_lmk / lmk_sample) <strong>서로 객체 접근 권한 부여하는 방법</strong>에 대해서 알아보자💡</p>
<blockquote>
<p><strong>1. (sample) kh_lmk 계정의 EMPLOYEE 테이블 조회</strong></p>
</blockquote>
<pre><code class="language-sql">SELECT * FROM kh_lmk.EMPLOYEE;
-- ORA-00942: 테이블 또는 뷰가 존재하지 않습니다
--&gt; 접근 권한이 없어서 조회 불가</code></pre>
<p>** 2. (kh_lmk) sample 계정에 EMPLOYEE 테이블 조회 권한 부여**
✔ 객체 권한 부여 방법
<code>GRANT 객체권한 ON 객체명 TO 사용자명;</code></p>
<pre><code class="language-sql">GRANT SELECT ON EMPLOYEE TO lmk_sample;</code></pre>
<p>** 3. (sample) 다시 EMPLOYEE 조회**</p>
<pre><code class="language-sql">SELECT * FROM kh_lmk.EMPLOYEE;</code></pre>
<p><strong>4. (kh_lmk) sample 계정에 부여한 EMPLOYEE 테이블 조회 권한 회수 (REVOKE)</strong>
📑 권한 회수 작성법
<code>REVOKE 객체권한 ON 객체명 FROM 사용자명;</code></p>
<pre><code class="language-sql">REVOKE SELECT ON EMPLOYEE FROM lmk_sample;</code></pre>
<p><strong>5. (sample) 권한 회수 확인</strong></p>
<pre><code class="language-sql">SELECT * FROM kh_lmk.EMPLOYEE;
-- ORA-00942: 테이블 또는 뷰가 존재하지 않습니다</code></pre>
<hr>
<hr>
<blockquote>
<p><strong>✍ 시험보기 전 DCL 다시 정리해보기!</strong></p>
</blockquote>
<pre><code>&lt;계정 추가하고 접속 권한을 부여하는 방법&gt;

&lt;계정을 추가하는 방법&gt;
CREATE USER 사용자명 IDENTIFIED BY 비밀번호!

&lt;접속 권한을 부여하는 방법&gt;
GRANT CREATE SESSION TO (권한을 줄 계정의) 사용자명!

&lt;테이블을 생성할 권한을 부여하는 방법&gt;
GRANT CREATE TABLE TO 사용자명

그리고 
&lt;해당 사용자가 무제한으로 공간을 사용할 수 있는 권한을 제공하는 방법&gt;
ALTER USER 사용자계정 DEFAULT TABLESPACE 
SYSTEM QUOTA UNLIMITED ON SYSTEM;


&lt;계정에 CONNECT, RESOURCE 부여하기!&gt;

CONNECT는 접속 관련 권한을 묶어둔 ROLE이며, 
RESOURCE은 사용을 위한 기본 객체 생성 권한을 묶어둔 ROLE이다.

GRANT CONNECT, RESOURSE TO 사용자계정명


&lt;객체에 권한을 부여하는 방법&gt;
&lt;sample계정에 있는 EMPLOYEE 테이블을 kh_cmh 계정을 통해 조회해보기&gt;
SELECT * FROM kh_cmh.EMPLOYEE;
---&gt; 조회 시 존재하지 않는다고 오류가 발생하는데, 접근할 수 있는 권한이 없기에 조회가 불가능하다.
따라서, sample계정에서 객체에 권한을 부여해줘야함!

&lt;테이블 조회 권한을 부여하는 방법&gt;
GRANT 객체 권한 (여기서는 SELECT임! SELECT 문이기에!) ON 객체명!
(해당구문에서는 테이블명이 해당된다.) EMPLOYEE TO 사용자명! 

객체 권한을 회수하는 방법은 뭐가 있을까?!
REVOKE 를 사용하면 된다.
&lt;객체 권한 회수 작성법!&gt;
REVOKE (객체권한)SELECT ON (객체명=테이블명)EMPLOYEE FROM 사용자명</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[INDEX]]></title>
            <link>https://velog.io/@minni_/INDEX</link>
            <guid>https://velog.io/@minni_/INDEX</guid>
            <pubDate>Tue, 12 Mar 2024 07:02:36 GMT</pubDate>
            <description><![CDATA[<h2 id="📘-index색인">📘 INDEX(색인)</h2>
<blockquote>
<p><strong>SQL 명령문 중 SELECT의 처리 속도를 향상 시키기 위해 컬럼에 대해서 생성하는 객체</strong>
▶ 인덱스 내부 구조는 B* 트리 형식으로 되어있음.</p>
</blockquote>
<p>📖 <strong>인덱스 생성방법</strong></p>
<blockquote>
<p>⭕ <strong>인덱스 장점</strong>
◾ 이진 트리 형식으로 구성되어 있어서 자동정렬 및 검색 속도가 빠름
◾ 조회 시 전체 테이블 내용을 조회하는 것이 아니라 인덱스가 지정된 컬럼만을 이용해서 조회하기 때문에 시스템 부하가 낮아져 전체적인 성능 향상이 된다.<br><vr>
  ❌ <strong>인덱스 단점</strong>
◾ 데이터 변경(INSERT, UPDATE, DELETE)이 비번한 경우 오히려 성능이 저하되는 문제가 발생
◾ 인덱스도 하나의 객체이기 때문에 이를 저장하기 위한 별도의 공간(메모리공간)이 필요함.
◾ 인덱스 생성 시간도 어느정도 필요함.</p>
</blockquote>
<p>📑 <strong>작성법</strong>
<strong><code>CREATE INDEX 인덱스명 
ON 테이블명 (컬럼명, 컬럼명, ...)</code></strong></p>
<p>👀 인덱스가 자동으로 생성되는 경우/ PK 또는 UNIQUE 제약조건이 설정되어있는 경우!</p>
<p><strong>인덱스를 이용한 검색 방법</strong>❓
➡ WHERE 절에 인덱스가 지정된 컬럼을 언급하면 된다.</p>
<pre><code class="language-sql">SELECT * FROM EMPLOYEE
WHERE EMP_ID = 215; ▶ 인덱스를 사용한 방법!

SELECT * FROM EMPLOYEE
WHERE EMP_NAME = &#39;대북혼&#39;;
▶ 인덱스를 사용하지 않는 방법!

◾ 인덱스 확인용 테이블 생성
CREATE TABLE TB_IDEX_TEST(
TEST_NO NUMBER PRIMARY KEY, --자동으로 인덱스가 생성됨
TEST_ID VARCHAR2(20) NOT NULL
);


--------------▶
◾ TB_IDX_TEST 테이블에 샘플데이터 100만개 삽입 (PL/ SQL 사용)

BEGIN 
    FOR I IN 1..1000000
    LOOP 
        INSERT INTO TB_IDEX_TEST VALUES(I,&#39;TEST&#39;||I);
    END LOOP;

    COMMIT;
END;



◾ 샘플데이터 100만개 확인
SELECT  COUNT(*) FROM TB_IDEX_TEST;


◾ 위 샘플데이터로 &#39;TEST500000&#39; 찾기


-- ▶ INDEX 사용 안했을 때
SELECT  * FROM TB_IDEX_TEST
WHERE TEST_ID = &#39;TEST500000&#39;; -- 0.014s

-- ▶ INDEX 사용했을 때
SELECT * FROM TB_IDEX_TEST
WHERE TEST_NO = 500000; -- 0.000s</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[SEQUENCE]]></title>
            <link>https://velog.io/@minni_/SEQUENCE</link>
            <guid>https://velog.io/@minni_/SEQUENCE</guid>
            <pubDate>Tue, 12 Mar 2024 06:05:02 GMT</pubDate>
            <description><![CDATA[<h2 id="📘-sequence-순서-연속-수열">📘 SEQUENCE (순서, 연속, 수열)</h2>
<blockquote>
<p><strong>순차적 번호 자동 발생기 역할의 객체</strong>
➡ SEQUENCE 객체를 이용해서 호출하게 되면 지정된 범위 내에서 일정한 간격으로 증가하는 숫자가 순차적으로 출력됨.
<vr>
 <code>EX) 1부터 10까지 1씩 증가하고 반복하는 시퀀스 객체
 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 ...</code></p>
</blockquote>
<p> 💡 SEQUENCE는 주로 PK역할의 컬럼에 삽입되는 값을 만드는 용도로 사용
<br></p>
<blockquote>
<p>📑 <strong>작성법</strong>
 <strong><code>CREATE SEQUENCE 시퀀스이름</code></strong>
  <vr>
 ▶ <code>START WITH 숫자</code> -- 처음 발생시킬 시작값 지정, 생략하면 기본값 1 부터 시작
 ▶ <code>INCREMENT BY 숫자</code> -- 다음 값에 대한 증가치, 생략하면 자동 1이 기본
 ▶<code>MAXVALUE 숫자 | NOMAXVALUE</code> -- 발생시킬 최대값 지정 (10의 27승 -1)
 ▶ <code>MINVALUE 숫자 | NOMINVALUE</code> -- 최소값 지정 (-10의 26승)
 ▶ <code>CYCLE | NOCYCLE</code> -- 값 순환 여부 지정
 ▶ <code>CACHE 바이트크기] | NOCACHE</code> -- 캐시메모리 기본값은 20바이트, 최소값은 2바이트</p>
</blockquote>
<p>시퀀스 캐시메모리는 할당된 크기만큼 미리 다음 값들을 생성해 저장해둠!
➡ 시퀀스 호출 시 미리 저장되어진 값들을 가져와 반환하므로 매번 시퀀스를 생성해서 반환하는 것보다 DB속도가 향상됨  </p>
<br>


<p>** 📖 시퀀스 사용방법 **</p>
<p>1) <strong><code>시퀀스명.NEXTVAL</code></strong> : 다음 시퀀스 번호를 얻어옴. (INCREMENT BY만큼 증가된 값)
 <strong>단, 시퀀스 생성 후 첫 호출인 경우 START WITH의 값을 얻어옴.</strong></p>
<p>2) <strong><code>시퀀스명.CURRVAL</code></strong> : 현재 시퀀스 번호를 얻어옴.
<strong>단, 시퀀스 생성 후 NEXTVAL 호출 없이 CURRVAL를 호출하면 오류 발생.</strong></p>
<br>  

<p>** ✔ 옵션 없이 SEQUENCE 생성 **</p>
<blockquote>
<p><strong>범위 : 1 ~ 최대값
시작 : 1
반복 X (CYCLE)
캐시메모리 20BYTE (기본값)</strong></p>
</blockquote>
<pre><code class="language-sql">CREATE SEQUENCE SEQ_TEST;</code></pre>
<p> 📣 <strong>CURRVAL 주의사항</strong> </p>
<p>▶ CURRVAL는 마지막 NEXTVAL 호출 값을 다시 보여주는 기능
<strong>따라서,</strong> NEXTVAL를 먼저 호출해야 CURRVAL 호출이 가능하다 👌 </p>
<pre><code class="language-sql">◾ 생성 하자마자 바로 현재 값 확인
SELECT SEQ_TEST.CURRVAL FROM DUAL;
-- ORA-08002: 시퀀스 SEQ_TEST.CURRVAL은 이 세션에서는 정의 되어 있지 않습니다
WHY? 
▶NEXTVAL이 안되어 있기에 보여줄 값이 없음! 따라서, 시퀀스 만들고 나서 NEXTVAL을 꼭 호출해야한 후 CURRVAL를 사용하면 됨.

SELECT SEQ_TEST.NEXTVAL FROM DUAL; -- 1
SELECT SEQ_TEST.CURRVAL FROM DUAL; --1

SELECT SEQ_TEST.NEXTVAL FROM DUAL; -- 2
SELECT SEQ_TEST.NEXTVAL FROM DUAL; -- 3
SELECT SEQ_TEST.NEXTVAL FROM DUAL; -- 4
SELECT SEQ_TEST.NEXTVAL FROM DUAL; -- 5
SELECT SEQ_TEST.CURRVAL FROM DUAL; --5 (마지막NEXTVAL값이 5이기에 CURRVAL에서 조회했을 때 5의 값이 나옴)</code></pre>
<p>▶**  👩‍💻 실제 사용 예시**</p>
<pre><code class="language-sql">CREATE TABLE EMP_TEMP
AS SELECT EMP_ID, EMP_NAME FROM EMPLOYEE;

SELECT * FROM EMP_TEMP;


-- 223번부터 10씩 증가하는 시퀀스 생성
CREATE SEQUENCE SEQ_TEMP 
START WITH 223 --&gt; 223부터 시작하겠다!
INCREMENT BY 10 -- 10씩 증가할 것이다.
NOCYCLE -- 반복을 X ( 기본값이라서 안써도 된다.)
NOCACHE; -- 캐시 사용을 X (지정한 값으로 안쓴다는 말임 CACHE의 기본값 20이 되어있음)

-- EMP_TEMP 테이블에 사원 정보 삽입
INSERT INTO EMP_TEMP VALUES(SEQ_TEMP.NEXTVAL, &#39;홍길동&#39;); --223
INSERT INTO EMP_TEMP VALUES(SEQ_TEMP.NEXTVAL, &#39;김지유&#39;); --233
INSERT INTO EMP_TEMP VALUES(SEQ_TEMP.NEXTVAL, &#39;김지한&#39;); --244

SELECT * FROM EMP_TEMP
ORDER BY EMP_ID DESC;</code></pre>
<hr>
<h3 id="📖-sequence-수정">📖 SEQUENCE 수정</h3>
<blockquote>
<p>** 📑 작성법 **
  <vr>
 ▶ <code>ALTER SEQUENCE 시퀀스이름</code>
 ▶ <code>INCREMENT BY 숫자</code> : 다음 값에 대한 증가치, 생략하면 자동 1이 기본
 ▶  <code>MAXVALUE 숫자 | NOMAXVALUE</code> :  발생시킬 최대값 지정 (10의 27승 -1)
 ▶ <code>MINVALUE 숫자 | NOMINVALUE</code> :  최소값 지정 (-10의 26승)
 ▶ <code>CYCLE | NOCYCLE</code> :  값 순환 여부 지정
 ▶ <code>CACHE 바이트크기 | NOCACHE</code> :  캐시메모리 기본값은 20바이트, 최소값은 2바이트</p>
</blockquote>
<pre><code class="language-sql">◾ SEQ_TEMP를 1씩 증가하는 형태로 변경
ALTER SEQUENCE  SEQ_TEMP
INCREMENT  BY 1;

INSERT INTO EMP_TEMP VALUES(SEQ_TEMP.NEXTVAL, &#39;나보윤&#39;); --244
INSERT INTO EMP_TEMP VALUES(SEQ_TEMP.NEXTVAL, &#39;이민경&#39;); --245
INSERT INTO EMP_TEMP VALUES(SEQ_TEMP.NEXTVAL, &#39;강다솔&#39;); --246

SELECT  * FROM EMP_TEMP 
ORDER BY 1 DESC;</code></pre>
<p>📑 <strong>테이블, 뷰, 시퀀스 삭제</strong><br><code>DROP TABLE/VIEW/SEQUENCE + 해당명;</code></p>
<pre><code class="language-sql">DROP TABLE EMP_TEMP; --테이블 삭제
DROP VIEW V_DCOPY2; -- 뷰 삭제
DROP SEQUENCE SEQ_TEMP; -- 시퀀스 삭제</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[VIEW]]></title>
            <link>https://velog.io/@minni_/VIEW</link>
            <guid>https://velog.io/@minni_/VIEW</guid>
            <pubDate>Tue, 12 Mar 2024 05:12:44 GMT</pubDate>
            <description><![CDATA[<h1 id="view">VIEW</h1>
<blockquote>
<ul>
<li>SELECT문의 <strong>실행 결과(RESULT SET)를 화면에 저장하는 객체</strong> !</li>
</ul>
</blockquote>
<ul>
<li>VIEW를 <strong>논리적 가상 테이블</strong>이라고도 하는데, <strong>테이블 모양을 하고는 있지만, 실제로 값을 저장하고 있지는 않다는 것</strong>을 말한다.</li>
</ul>
<p>** ✔  VIEW의 사용목적** ❓</p>
<p> 1) 복잡한 SELECT문을 쉽게 재사용하기 위해서 사용
 2) 테이블의 진짜 모습을 감출 수 있어 보안상 유리함.</p>
<p>📣 <strong>VIEW 사용 시 주의사항</strong></p>
<p> 1) 가상 테이블(실제 테이블 X)이라서 ALTER 구문의 사용이 불가능 함.
 2) VIEW를 이용한 DML(INSERT/UPDATE/DELETE)이 가능한 경우도 있지만, 많은 제약이 따르기 때문에 SELECT 용도로 사용하는 것을 권장함.</p>
<p>** ✔ VIEW 생성 방법**
 <code>CREATE [OR REPLACE [FORCE || NOFORCE] ] VIEW 뷰이름
  AS SUBQUERY(만들고 싶은 뷰 모양의 SUBQUERY) 
 [WITH CHCK OPTION]
 [WITH READ ONLY]</code></p>
<h4 id="✔--view에-들어가는-옵션-종류">✔  VIEW에 들어가는 옵션 종류</h4>
<blockquote>
<p><strong>1) OR REPLACE</strong> : 기존에 동일한 뷰이름이 존재하는 경우 덮어쓰고, 존재하지 않으면 새로 생성.
<br>
** 2) FORCE || NOFORCE **
▫  <strong>FORCE</strong> : 서브쿼리에 사용된 테이블이 존재하지 않아도 뷰 생성.
▫ <strong>NOFORCE</strong> : 서브쿼리에 사용된 테이블이 존재해야만 뷰 생성(기본값)
<br>
<strong>3) WITH CHCK OPTION</strong> : 옵션에 설정한 컬럼의 값을 수정 불가능하게 함.
<br>
<strong>4) WITH READ ONLY</strong> : 뷰에 대해 조회만 가능(DML 수행 불가)</p>
</blockquote>
<br>

<p>📑 <strong>사번, 이름, 부서명, 직급명 조회 결과를 저장하는 VIEW 생성</strong></p>
<blockquote>
<pre><code class="language-sql">CREATE VIEW V_EMP
AS SELECT EMP_ID, EMP_NAME, DEPT_TITLE, JOB_NAME
        FROM EMPLOYEE
        JOIN DEPARTMENT ON(DEPT_CODE =DEPT_ID)
        JOIN JOB USING(JOB_CODE);
        --▶ ORA-01031: 권한이 불충분합니다</code></pre>
</blockquote>
<pre><code>🤷‍♀️**오류 해결방법**
1) SYS 관리자 계정으로 접속함.
2) ALTER SESSION SET &quot;_ORACLE_SCRIPT&quot; = TRUE;
3) GRANT CREATE VIEW TO kh_lmk;
4) 권한 부여 받은 kh계정으로 접속하여 위 VIEW 생성 구문 다시 실행    
```sql
ALTER SESSION SET &quot;_ORACLE_SCRIPT&quot; = TRUE;
GRANT CREATE VIEW TO kh_lmk;</code></pre><pre><code class="language-sql">◾ 생성된 VIEW를 이용하여 조회
SELECT  * FROM V_EMP;</code></pre>
<hr>
<p>📑VIEW를 이용한 DML 확인</p>
<pre><code class="language-sql">◾ 테이블 복사 
CREATE TABLE DEPT_COPY2
AS SELECT * FROM DEPARTMENT;
--
◾ 복사한 테이블을 이용해서 VIEW 생성
CREATE OR REPLACE VIEW V_DCOPY2
AS SELECT DEPT_ID, LOCATION_ID FROM DEPT_COPY2;
--
◾ 뷰 생성 확인
SELECT * FROM V_DCOPY2;
--
◾ 뷰를 이용한 INSERT
INSERT INTO V_DCOPY2 VALUES(&#39;D0&#39;,&#39;L3&#39;);
--
◾ 삽입 확인
SELECT * FROM V_DCOPY2; -- VIEW에 &#39;D0&#39;가 삽입된걸 확인
--▶ 가상의 테이블인 VIEW에 데이터 삽입이 가능한 걸까? X
--
◾ 원본 데이블 확인
SELECT * FROM DEPT_COPY2; -- &#39;D0&#39;, NULL ,&#39;L3&#39;
--▶ VIEW에 삽입한 내용이 원본 테이블에 존재하는 것 확인함.
--▶ VIEW를 이용한 DML 구문이 원본에 영향을 미친다!
--
◾ VIEW의 본래 목적인 보여지는 것(조회)이라는 용도에 맞게 사용하는 게 좋다.
--▶ WITH READ ONLY 옵션 사용
CREATE OR REPLACE VIEW V_DCOPY2
AS SELECT DEPT_ID, LOCATION_ID FROM DEPT_COPY2
WITH READ ONLY; -- 읽기 전용 VIEW 생성(SELECT만 가능)
--
INSERT INTO V_DCOPY2 VALUES(&#39;D0&#39;,&#39;L3&#39;);
 --▶ ORA-42399: 읽기 전용 뷰에서는 DML 작업을 수행할 수 없습니다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[DDL]]></title>
            <link>https://velog.io/@minni_/DDL</link>
            <guid>https://velog.io/@minni_/DDL</guid>
            <pubDate>Tue, 12 Mar 2024 02:50:28 GMT</pubDate>
            <description><![CDATA[<h1 id="ddldata-definition-language">DDL(Data Definition Language)</h1>
<blockquote>
<p>객체를 만들고(CREATE), 바꾸고(ALTER), 삭제(DROP) 하는 데이터 정의 언어</p>
</blockquote>
<h3 id="📕-alter바꾸다-수정하다-변조하다">📕 ALTER(바꾸다, 수정하다, 변조하다)</h3>
<blockquote>
<p>▶ 테이블에서 수정할 수 있는 것
<br></p>
</blockquote>
<p> 1) 제약조건(추가/ 삭제)
 2) 컬럼(추가/수정/삭제)
 3) 이름 변경 (테이블명, 컬럼명 ...)</p>
<h3 id="1-제약-조건-추가-삭제">1. 제약 조건 (추가/ 삭제)</h3>
<p><strong>[작성법]</strong></p>
<p><strong>(1) 추가</strong> : <code>ALTER TABLE 테이블명</code>
<code>ADD [CONSTRAINT 제약조건명] 제약조건 (지정할 컬럼명) [REFERENCES 테이블명 [(컬럼명)]];</code>  ◀ FK(FOREIGN KEY) 인 경우 추가</p>
<p><strong>(2) 삭제</strong> : <code>ALTER TABLE 테이블명 DROP CONSTRAINT 제약조건명 ;</code>
▶ 제약조건 자체를 수정하는 구문은 별도 존재하지 않음! ➡  삭제 후 추가를 해야함.</p>
<pre><code class="language-sql">◾ DEPARTMENT 테이블 복사(컬럼명, 데이터타입, NOT NULL만 복사)
CREATE TABLE DEPT_COPY 
AS SELECT * FROM DEPARTMENT;

SELECT * FROM DEPT_COPY;

◾ DEPT_COPY의 DEPT_TITLE 컬럼에 UNIQUE 추가
ALTER TABLE DEPT_COPY 
ADD CONSTRAINT DEPT_COPY_TITLE_U UNIQUE(DEPT_TITLE);


◾DEPT_COPY의 DEPT_TITLE 컬럼에 있는 UNIQUE 조건 삭제하기
ALTER TABLE DEPT_COPY 
DROP CONSTRAINT DEPT_COPY_TITLE_U;

✔ 👩‍💻 DEPT_COPY의 DEPT_TITLE 컬럼에 NOT NULL 제약조건 추가/ 삭제
ALTER TABLE DEPT_COPY
ADD CONSTRAINT DEPT_COPY_TITLE_NN NOT NULL(DEPT_TITLE);
➡ ORA-00904: : 부적합한 식별자
➡ NOT NULL 제약조건은 새로운 조건을 추가하는 것이 아닌 컬럼 자체에 NULL 허용/ 비허용을 제어하는 성질 변경의 형태로 인식됨.

◾ MODIFY (수정하다) 구문을 사용해서 NULL 제어
ALTER TABLE DEPT_COPY 
MODIFY DEPT_TITLE NOT NULL; ➡ DEPT_TITLE 컬럼을 NOT NULL로 수정

ALTER TABLE DEPT_COPY 
MODIFY DEPT_TITLE NULL;</code></pre>
<hr>
<h3 id="2-컬럼-추가-수정-삭제">2. 컬럼 (추가/ 수정/ 삭제)</h3>
<blockquote>
<p>[컬럼 추가]
<code>ALTER TABLE 테이블명 ADD(컬럼명 데이터타입 [DEFAULT &#39;값&#39;]);</code>
<br>
[컬럼 수정]
<code>ALTER TABLE 테이블명 MODIFY 컬럼명 데이터 타입;</code> ➡ 데이터 타입 변경
<code>ALTER TABLE 테이블명 MODIFT 컬럼명 DEFAULT &#39;값&#39;;</code> ➡ DEFAULT 값 변경
<br>
[컬럼 삭제]
<code>ALTER TABLE 테이블명 DROP (삭제할컬럼명);</code>
<code>ALTER TABLE 테이블명 DROP COLUMN 삭제할컬럼명;</code></p>
</blockquote>
<pre><code class="language-sql">SELECT * FROM DEPT_COPY;

◾ CNAME 컬럼 추가
ALTER TABLE DEPT_COPY ADD (CNAME VARCHAR2(30));

◾ LNAME 컬럼 추가 (기본값 &#39;한국&#39;)
ALTER TABLE DEPT_COPY ADD (LNAME VARCHAR2(30) DEFAULT &#39;한국&#39;);
➡ 컬럼이 생성되면서 DEFAULT 값이 자동 삽입됨.

◾ D10 개발 1팀 추가하기
INSERT INTO DEPT_COPY 
VALUES (&#39;D10&#39;,&#39;개발1팀&#39;,&#39;L1&#39;,DEFAULT,DEFAULT);
◾ ORA-12899: &quot;KH_LMK&quot;.&quot;DEPT_COPY&quot;.&quot;DEPT_ID&quot; 열에 대한 값이 너무 큼(실제: 3, 최대값: 2)</code></pre>
<pre><code class="language-sql">◾ DEPT_ID 컬럼 데이터 타입 수정 
ALTER TABLE DEPT_COPY MODIFY DEPT_ID VARCHAR2(3);
➡ 다시 위 INSERT 실행 ➡ 성공

SELECT * FROM DEPT_COPY;

◾ LNAME의 기본값을 &#39;KOREA&#39;로 수정
ALTER TABLE DEPT_COPY MODIFY LNAME DEFAULT &#39;KOREA&#39;;
SELECT * FROM DEPT_COPY; 
➡ 기본 값을 변경했다고 해서 기존 데이터가 변하지는 않음

◾ LNAME &#39;한국&#39; -&gt; &#39;KOREA&#39;로 변경 
UPDATE DEPT_COPY SET 
LNAME = DEFAULT
WHERE LNAME = &#39;한국&#39;;

SELECT * FROM DEPT_COPY; ➡ UPDATE 확인
COMMIT;

◾ 모든 컬럼 삭제
ALTER TABLE DEPT_COPY DROP(LNAME);
ALTER TABLE DEPT_COPY DROP COLUMN CNAME;
ALTER TABLE DEPT_COPY DROP(LOCATION_ID);
ALTER TABLE DEPT_COPY DROP(DEPT_TITLE);
ALTER TABLE DEPT_COPY DROP(DEPT_ID);
◾ ORA-12983 : 테이블에 모든 열들을 삭제할 수 없습니다</code></pre>
<p><strong>💡 컬럼 삭제 시 유의사항</strong></p>
<blockquote>
</blockquote>
<p><strong>테이블이란</strong> ❓
행과 열로 이루어진 DB의 가장 기본적인 객체 테이블에 데이터가 저장됨.
➡ 따라서, 테이블은 최소 1개 이상의 컬럼이 존재해야 되기 때문에 모든 컬럼을 다 삭제할 수는 없다.</p>
<pre><code class="language-sql">◾ 테이블 삭제
DROP TABLE DEPT_COPY;
SELECT * FROM DEPT_COPY;
- ORA-00942: 테이블 또는 뷰가 존재하지 않습니다.</code></pre>
<pre><code class="language-sql">◾ DEPARTMENT 테이블 복사해서 DEPT_COPY 생성
◾ DEPT_COPY 테이블에 PK 추가 (컬럼 : DEPT_ID, 제약조건명 : D_COPY_PK)
CREATE TABLE DEPT_COPY
AS SELECT  * FROM DEPARTMENT;
➡ 컬럼명, 데이터 타입, NOT NULL 여부만 복사</code></pre>
<pre><code class="language-sql">◾ DEPT_COPY 테이블에 PK 추가 (컬럼 : DEPT_ID, 제약조건명 : D_COPY_PK)
ALTER TABLE DEPT_COPY ADD CONSTRAINT D_COPY_PK PRIMARY KEY (DEPT_ID);</code></pre>
<hr>
<h3 id="3-이름-변경컬럼-테이블-제약조건명">3. 이름 변경(컬럼, 테이블, 제약조건명)</h3>
<p><strong>1) 컬럼명 변경 (DEPT_TITLE -&gt; DEPT_ NAME)</strong></p>
<pre><code class="language-sql">ALTER TABLE DEPT_COPY RENAME COLUMN DEPT_TITLE TO DEPT_NAME;

SELECT * FROM DEPT_COPY;</code></pre>
<p><strong>2) 제약조건명 변경 (D_COPY_PK -&gt; DEPT_COPY_PK)</strong></p>
<pre><code class="language-sql">ALTER TABLE DEPT_COPY RENAME CONSTRAINT D_COPY_PK TO DEPT_COPY_PK;

SELECT * FROM DEPT_COPY;</code></pre>
<p><strong>3) 테이블명 변경(DEPT_COPY -&gt; DCOPY)</strong></p>
<pre><code class="language-sql">ALTER TABLE DEPT_COPY RENAME TO DCOPY;

SELECT * FROM DEPT_COPY;
➡ ORA-00942: 테이블 또는 뷰가 존재하지 않습니다 ▶오류발생 !
SELECT * FROM DCOPY;</code></pre>
<hr>
<h3 id="4-테이블-삭제">4. 테이블 삭제</h3>
<p><code>DROP TABLE 테이블명 [CASCADE CONSTRAINTS];</code></p>
<p><strong>1) 관계가 형성되지 않은 테이블 삭제</strong></p>
<pre><code class="language-sql">DROP TABLE DCOPY;</code></pre>
<p><strong>2) 관계가 형성된 테이블 삭제</strong></p>
<pre><code class="language-sql">CREATE TABLE TB1(
    TB1_PK NUMBER PRIMARY KEY,
    TB1_COL NUMBER
);

CREATE TABLE TB2(
    TB2_PK NUMBER PRIMARY KEY,
    TB_COL NUMBER REFERENCES TB1
);

◾ TB1에 샘플데이터 삽입
INSERT INTO TB1 VALUES(1,100);
INSERT INTO TB1 VALUES(2,200);
INSERT INTO TB1 VALUES(3,300);

COMMIT;

◾ TB2에 샘플 데이터 삽입 
INSERT INTO TB2 VALUES(11, 1);
INSERT INTO TB2 VALUES(12, 2);
INSERT INTO TB2 VALUES(13, 3);

◾ TB1 삭제 
DROP TABLE TB1;
▶ ORA-02449: 외래 키에 의해 참조되는 고유/기본 키가 테이블에 있습니다

💡 해결방법 
1) 자식테이블 먼저 삭제 후 부모 테이블 삭제하면 됨( 자식, 부모 순서로 삭제)
2) ALTER를 이용해서 FORGIGN KEY 제약조건 삭제 후 TB1 삭제하기
3) DROP TABLE 삭제옵션 CASCADE CONSTAINTS 사용
➡ CASCADE CONSTRAINTS : 삭제하려는 테이블과 연결된 FK 제약조건을 모두 삭제하는 것임.

DROP TABLE TB1 CASCADE CONSTRAINTS;
➡ 삭제 성공

SELECT  * FROM TB1 ; ➡ 삭제확인
SELECT  * FROM TB2 ; ➡ 삭제확인
</code></pre>
<hr>
<h3 id="📣-ddl-주의사항">📣 DDL 주의사항</h3>
<blockquote>
</blockquote>
<ol>
<li>DDL은 <strong>COMMIT/ROLLBACK이 되지 않는다</strong>. 따라서, ALTER, DROP을 <strong>신중하게</strong> 진행해야함.<br></li>
<li>DDL과 DML <strong>구문 섞어서 수행하면 안된다.</strong>
➡ DDL은 수행 시 존재하고 있는 트랜잭션을 <strong>모두 DB에 강제 COMMIT</strong> 시킴
➡ <strong>DDL 이 종료된 후</strong> <strong>DML구문</strong>을 <strong>수행</strong>할 수 있도록 <strong>권장</strong>!<pre><code class="language-sql">SELECT * FROM TB2;
COMMIT;</code></pre>
</li>
</ol>
<hr>
<p>◾ DML
INSERT INTO TB2 VALUES(14,4);
INSERT INTO TB2 VALUES(15,5);
SELECT  * FROM TB2;</p>
<hr>
<p>◾ 컬럼명 변경 DDL
ALTER TABLE TB2 RENAME COLUMN TB2_COL TO TB2_COLCOL;
ROLLBACK ;
SELECT * FROM TB2;
```</p>
]]></description>
        </item>
    </channel>
</rss>