<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>JILOG_94.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 23 Jun 2023 10:25:37 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>JILOG_94.log</title>
            <url>https://velog.velcdn.com/images/jilog_94/profile/50d501a0-fe63-4822-b67f-6a3f6fefa340/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. JILOG_94.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jilog_94" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[CS - CPU와 메모리]]></title>
            <link>https://velog.io/@jilog_94/CS-CPU%EC%99%80-%EB%A9%94%EB%AA%A8%EB%A6%AC</link>
            <guid>https://velog.io/@jilog_94/CS-CPU%EC%99%80-%EB%A9%94%EB%AA%A8%EB%A6%AC</guid>
            <pubDate>Fri, 23 Jun 2023 10:25:37 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-06-23">2023-06-23</h1>
<hr>
<h2 id="cpu">CPU</h2>
<p>( Central Processing Unit ) - <code>중앙 처리 장치</code> ( 컴퓨터의 두뇌 )
컴퓨터 시스템을 통제하고 프로그램의 <code>연산을 실행/처리</code>하는 가장 핵심적인 컴퓨터의 제어 장치</p>
<h3 id="alu">ALU</h3>
<p>( Arithmetic Logic Unit ) - <code>산술 논리 연산장치</code>
<code>비교, 판단, 연산</code> 수행</p>
<h3 id="cu">CU</h3>
<p>( Control Unit )
명령어를 실행하는 <code>순서를 제어</code>하고 스케줄링</p>
<h4 id="▲-제어부">▲ 제어부</h4>
<p>주기억장치에 저장되어 있는 명령어를 순서대로 호출하여 해독하고, 제어 신호를 발생시켜 각 장치를 동작하도록 함</p>
<h4 id="▲-내부버스">▲ 내부버스</h4>
<p>CPU와 제어부 사이를 연결하는 버스 (통로)</p>
<h3 id="memory-unit">Memory Unit</h3>
<h4 id="▲-registers">▲ Registers</h4>
<p>연산에 필요한 데이터를 저장하고 빠른 속도로 접근할 수 있는 저장공간</p>
<ol>
<li>범용 레지스터 : 연산에 필요한 데이터나 연산 결과를 임시로 저장</li>
<li>특수목적 레지스터 : 특별한 용도로 사용하는 레지스터</li>
</ol>
<h4 id="▲-l1--캐시-메모리-">▲ L1 ( 캐시 메모리 )</h4>
<p>처리 속도를 높여주는 역할</p>
<hr>
<h2 id="cpu-성능">CPU 성능</h2>
<p><code>4.5Hz 클럭, 듀얼코어</code></p>
<h3 id="클럭">클럭</h3>
<p>CPU 내부에서 일정한 주파수를 가지는 신호</p>
<ul>
<li><code>4.5Hz</code> = 1초에 45억 번의 명령어 처리 가능</li>
</ul>
<p>클럭 주파수가 빠를수록 더 많은 명령을 처리할 수 있기 때문에 더 좋을 성능의 중앙 처리 장리하고 할 수 있으나, 빠를수록 발열이 심해지며 쿨링을 더 많이 해줘야하므로 전기 사용량이 높아짐
또한 오버클럭을 하는 경우 부품의 수명이 짧아질 수 있음</p>
<h3 id="코어">코어</h3>
<p>CPU 역할을 하는 블록을 뜻함</p>
<ul>
<li><code>듀얼코어</code> = CPU가 두 개! 많은 연산을 병렬 처리할 수 있음</li>
</ul>
<p>병렬 처리하므로 속도가 더 빠를 수 있지만 모든 처리를 병렬로 할 수 있는 것이 아니므로 프로그램을 구현할 때 동시에 수행할 수 있는 대상을 찾아 쓰레드를 만드는 작업, 쓰레드 간의 자원경쟁을 해소하기 위한 동기화 작업 등을 반드시 수행해줘야 함
클럭과 마찬가지로 발열이 심해지며 쿨링으로 인한 전기 사용량이 높아짐</p>
<hr>
<h2 id="메모리">메모리</h2>
<pre><code>        레지스터                -&gt; CPU
        ------
     캐시 ( SRAM )            -&gt; 주기억장치
     ------------
  메인 메모리 ( DRAM )        -&gt; 주기억장치
  -------------------
   하드디스크 ( HDD )            -&gt; 보조기억장치
-----------------------</code></pre><h3 id="캐시-메모리">캐시 메모리</h3>
<p>( SRAM ) - L2 , L3
<code>CPU 구성에 있는 캐시 메모리(L1)과 메모리그룹에 속한 캐시 메모리(L2,L3)는 다른 메모리</code>
메인 메모리에 있는 데이터를 캐시 메모리에 불러와 놓고 CPU가 필요한 데이터를 캐시에서 먼저 찾도록 하여 성능 향상
( CPU 레지스터와 비슷하지만 CPU 레지스터는 CPU 안에서 연산을 처리하기 위한 데이터 공간이고 L2,L3 캐시 메모리는 CPU와 별도 공간임 )</p>
<h3 id="주기억장치">주기억장치</h3>
<p>( DRAM ) - 메인메모리 - <code>RAM</code> ( Random Access Memory )
CPU가 사용하기 좋도록 현재 처리중인 데이터나 명령만을 일시적으로 저장하는 휘발성 메모리
-&gt; 컴퓨터 꺼지면 날아감
보조기억장치( HDD ) 보다 접근 속도가 빠름</p>
<h3 id="보조기억장치">보조기억장치</h3>
<p>( HDD ) - 하드디스크
데이터와 프로그램을 반영구적으로 저장
-&gt; 컴퓨터 꺼도 날아가지 않음</p>
<hr>
<h2 id="cpu--메모리-동작">CPU &amp; 메모리 동작</h2>
<blockquote>
<ol>
<li>주기억장치가 입력장치에서 입력받은 데이터 또는 보조기억장치에 저장된 프로그램을 읽어옴</li>
<li>CPU는 프로그램을 실행하기 위해 주기억장치에 저장된 프로그램 명령어와 데이터를 읽어와 처리하고 결과를 다시 주기억장치에 저장함</li>
<li>주기억장치는 처리 결과를 보조기억장치에 저장하거나 출력장치로 보내서 출력시킴</li>
<li>CPU 내의 제어장치(CU)가 1~3번 과정에서 명령어가 순서대로 실행되도록 각 장치들을 제어함</li>
</ol>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[WIL - 8주차 정리]]></title>
            <link>https://velog.io/@jilog_94/WIL-8%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jilog_94/WIL-8%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 28 May 2023 14:40:31 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-05-28">2023-05-28</h1>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[WIL - 6주차 정리]]></title>
            <link>https://velog.io/@jilog_94/WIL-6%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jilog_94/WIL-6%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 14 May 2023 15:43:53 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-05-15">2023-05-15</h1>
<hr>
<p>저번주부터 본격적으로 프론트엔드와 백엔드의 협업을 시작했다.
처음으로 해보는 협업이 재미도 있었지만
생각보다 프론트와 협업하며 고려해야할 부분이 많았는데
가장 중요한 것은 <code>소통</code> 이었다.
서로 수정사항이 있으면 바로바로 소통을 해야하고
매일 회의를 가지며 진행상황을 공유해야 큰 문제가 생기지 않는다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[WIL - 5주차 정리]]></title>
            <link>https://velog.io/@jilog_94/WIL-5%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jilog_94/WIL-5%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 07 May 2023 13:12:22 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-05-07">2023-05-07</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/jilog_94/post/804567bc-5c88-4f72-b1a1-bc1908d436ab/image.png" alt=""></p>
<h2 id="cors">CORS</h2>
<p>( Cross-Origin Resource Sharing )
웹개발의 신입 신고식이라고 할 정도로 CORS 는 누구나 한 번 정도는 겪게 됨
다른 출처의 리소스 공유에 대한 허용/비허용 정책</p>
<blockquote>
<p>Access to fetch at ‘<a href="https://myhomepage.com%E2%80%99">https://myhomepage.com’</a> from origin ‘<a href="https://localhost:3000%E2%80%99">https://localhost:3000’</a> has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.</p>
</blockquote>
<p>이 에러 메세지는 사실 브라우저의 SOP 정책에 따라 다른 출처의 리소스를 차단하면서 발생된 에러이며, CORS 는 다른 출처의 리소르를 얻기위한 해결 방안임
( SOP 정책을 위반해도 CORS 정책에 따르면 다른 출처의 리소스라도 허용함 )</p>
<h3 id="▲-origin">▲ Origin</h3>
<p>: 출처
Origin : <code>Protocol</code> + <code>Host</code> + <code>Port</code> 를 모두 합친 URL</p>
<pre><code>&lt; URL 구성 요소 &gt;
https://www.domain.com:3000/user?query=name&amp;page=1#first
-------|--------------|----|----|-----------------|-----
Protocol      Host       Port Path    Query string  Fragment
= Scheme</code></pre><p><code>Protocol</code> , <code>Scheme</code> : http, https, ftp, telnet
<code>Host</code> : 사이트 도메인
<code>Port</code> : 포트 번호
<code>Path</code> : 사이트 내부 경로
<code>Query string</code> : 요청의 key 와 value 값
<code>Fragment</code> : 해시 태그</p>
<h3 id="▲-sop">▲ SOP</h3>
<p>( Same-Origin Policy ) - 동일한 출처에 대한 정책
동일한 출처 서버에 있는 리소스를 가져올 수 있지만, 다른 출처 서버에 있는 리소스는 가져올 수 없음</p>
<ul>
<li>출처가 다른 두 개의 어플리케이션이 마음대로 소통할 수 있는 환경은 위험한 환경임
( 악의를 가진 사용자가 사용자 정보를 탈취하기가 너무 쉬워짐 )</li>
</ul>
<h2 id="preflight-request">Preflight Request</h2>
<p>: 예비 요청
브라우저는 요청을 보낼 때 한번에 바로 보내지 않고, 먼저 예비 요청을 보내 서버와 잘 통신되는지 확인한 후 본 요청을 보냄
( OPTIONS 메서드 사용 )</p>
<ul>
<li>그러나 결국 실제 요청에 걸리는 시간이 늘어나게 되어 어플리케이션 성능에 영향을 미침</li>
</ul>
<h2 id="simple-request">Simple Request</h2>
<p>: 단순 요청
예비 요청을 생략하고 바로 서버에 직행으로 본 요청을 보낸 후, 서버가 이에 대한 응답의 헤더에 Access-Control-Allow-Origin 헤더를 보내주면 브라우저가 CORS 정책 위반 여부를 검사하는 방식</p>
<ul>
<li><code>GET</code> , <code>HEAD</code> , <code>POST</code> 메서드만 가능</li>
<li>그 외 까다로운 조건들이 많기 때문에 단순 요청이 일어나는 상황은 거의 없음</li>
</ul>
<h2 id="해결-방안">해결 방안</h2>
<ol>
<li><code>서버에서 Access-Control-Allow_Origin 헤더 세팅하기</code><pre><code>// 스프링 서버 전역적으로 CORS 설정
@Configuration
public class WebConfig implements WebMvcConfigurer {
 @Override
 public void addCorsMappings(CorsRegistry registry) {
     registry.addMapping(&quot;/**&quot;)
         .allowedOrigins(&quot;http://localhost:8080&quot;, &quot;http://localhost:8081&quot;) // 허용할 출처
         .allowedMethods(&quot;GET&quot;, &quot;POST&quot;) // 허용할 HTTP method
         .allowCredentials(true) // 쿠키 인증 요청 허용
         .maxAge(3000) // 원하는 시간만큼 pre-flight 리퀘스트를 캐싱
 }
}
</code></pre></li>
</ol>
<p>// 특정 컨트롤러에만 CORS 적용하고 싶을때.
@Controller
@CrossOrigin(origins = &quot;*&quot;, methods = RequestMethod.GET) 
public class customController {</p>
<pre><code>// 특정 메소드에만 CORS 적용 가능
@GetMapping(&quot;/url&quot;)  
@CrossOrigin(origins = &quot;*&quot;, methods = RequestMethod.GET) 
@ResponseBody
public List&lt;Object&gt; findAll(){
    return service.getAll();
}</code></pre><p>}</p>
<pre><code>
2. `AWS (S3 호스팅)`
버킷-권한-교차 출처 리소스 공유 편집-텍스트 상자에 JSON CORS 규칙 입력</code></pre><p>[
  {
    &quot;AllowedHeaders&quot;: [
      &quot;Authorization&quot;
    ],
    &quot;AllowedMethods&quot;: [
      &quot;GET&quot;,
      &quot;HEAD&quot;
    ],
    &quot;AllowedOrigins&quot;: [
      &quot;<a href="http://www.example.com&quot;">http://www.example.com&quot;</a>
    ],
    &quot;ExposeHeaders&quot;: [
      &quot;Access-Control-Allow-Origin&quot;
    ]
  }
]</p>
<pre><code></code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[git.. github.. ]]></title>
            <link>https://velog.io/@jilog_94/git..-github</link>
            <guid>https://velog.io/@jilog_94/git..-github</guid>
            <pubDate>Sat, 06 May 2023 05:45:05 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-05-06">2023-05-06</h1>
<p>주특기 프로젝트 주차가 시작됐다.
같은 조가 된 분들과 인사를 하고 api 명세서를 작성하고 이제 시작해보자..! 하는데 생각치도 못한 git 이 우리를 자꾸 넘어뜨렸다.</p>
<p>구성원 모두가 git &amp; github 를 사용한 협업에 익숙치 않아서 생기는 문제라서 먼저 git 으로 협업하는 순서를 정리해 두려고 한다.</p>
<ol>
<li><p>fork</p>
</li>
<li><p>fork 해서 새로 생긴 내 repo clone</p>
<pre><code>git clone https://github.com/jihyeon117/hh99-miniproject8.git</code></pre></li>
<li><p>코드 작성</p>
</li>
<li><p>checkout branch</p>
<pre><code>git checkout -b kjh</code></pre></li>
<li><p>add</p>
<pre><code>git add .</code></pre></li>
<li><p>commit</p>
<pre><code>git commit -m &quot;Fix : --- 수정 완료&quot;</code></pre></li>
<li><p>github sync
( kjh sync 버튼 클릭 )</p>
</li>
<li><p>pull</p>
<pre><code>git pull origin kjh</code></pre></li>
<li><p>충돌 해결</p>
</li>
<li><p>add</p>
</li>
<li><p>commit</p>
</li>
<li><p>push</p>
<pre><code>git push origin kjh</code></pre></li>
<li><p>PR</p>
</li>
</ol>
<p>순서가 정확한지는 더 공부해봐야 알 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS S3]]></title>
            <link>https://velog.io/@jilog_94/AWS-S3</link>
            <guid>https://velog.io/@jilog_94/AWS-S3</guid>
            <pubDate>Fri, 05 May 2023 11:48:22 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-05-05">2023-05-05</h1>
<hr>
<h2 id="aws">AWS</h2>
<p>( Amazon Web Services )
아마존 클라우드 서비스</p>
<h3 id="▲-클라우드-서비스">▲ 클라우드 서비스</h3>
<p>실제로 매우 큰 데이터센터를 지어놓고 프로그램으로 그 리소스를 갖다 쓸 수 있게 하는 것</p>
<ul>
<li><p>확장성 : 직접 데이터센터를 구축할 필요 없이 필요한 만큼 쓰다가 필요하면 그만큼의 요금을 내고 원하는 만큼의 서비스 확장이 빠르게 가능함</p>
</li>
<li><p>탄력성 : 특정 시기에만 트래픽이 몰릴 수 있으므로 사람들이 많이 접속할 때만 리소스를 많이 썼다가 사람들이 빠지면 다시 되돌릴 수 있음</p>
</li>
<li><p>높은 접근성 : 언제 어디서든 클라우드에 접근하거나 서비스를 사용할 수 있음</p>
</li>
<li><p>장애 허용성 : 저장한 데이터를 한 곳에만 저장하지 않고 여러 공간에 나누어 저장하기 때문에 어느 한 곳에서 데이터가 없어지더라도 내가 저장한 데이터는 안전함</p>
</li>
</ul>
<h2 id="s3">S3</h2>
<p>( Simple Storage Service )
AWS 에서 제공하는 클라우드 스토리지 서비스로 영화, 비디오, 이미지 등 파일을 저장해두는 기능을 제공함</p>
<ul>
<li>파일을 저장해서 다른 곳에서 파일을 링크로 다운로드 받거나 API를 통해서 파일을 다운로드 받도록 해줌</li>
<li>정적 사이트 배포 기능을 통해 프론트엔드 페이지를 배포할 수 있도록 도와줌</li>
</ul>
<h3 id="▲-설정-방법">▲ 설정 방법</h3>
<ol>
<li>S3 버킷 생성</li>
<li>IAM ( Identity and Access Management ) 추가</li>
<li>dependency 추가</li>
<li>구현</li>
</ol>
<p><a href="https://velog.io/@_koiil/Springboot-AWS-S3%EB%A1%9C-%ED%8C%8C%EC%9D%BC-%EC%A0%80%EC%9E%A5%EC%86%8C-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0">참조 페이지</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[WIL - 4주차 정리]]></title>
            <link>https://velog.io/@jilog_94/WIL-4%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jilog_94/WIL-4%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 30 Apr 2023 14:20:35 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-04-30">2023-04-30</h1>
<hr>
<h2 id="orm">ORM</h2>
<p>( Object-Relational Mapping ) - 객체 관계 매핑</p>
<ul>
<li>객체가 RDB 테이블이 되도록 매핑 시켜주는 프레임워크</li>
<li><blockquote>
<p>SQL 쿼리가 아닌 직관적인 코드 (메서드) 로서 데이터를 조작할 수 있음</p>
</blockquote>
<pre><code>MySQL : SELECT * FROM USER;
ORM : user.findAll();</code></pre></li>
<li>쿼리를 작성하지 않고 메서드 호출만으로 쿼리가 수행되다 보니 생산성이 높아짐</li>
<li><blockquote>
<p>그러나 쿼리가 복잡해지면 ORM 으로 표현하는데 한계가 있음</p>
</blockquote>
</li>
</ul>
<hr>
<h2 id="sql">SQL</h2>
<p>( Structured Query Language ) - 구조적 쿼리 언어</p>
<ul>
<li>RDB 에 정보를 저장하고 처리하기 위한 프로그래밍 언어</li>
</ul>
<h3 id="■-dml">■ DML</h3>
<p>( Data Manipulation Language ) - 데이터 조작 언어</p>
<ol>
<li><code>SELECT</code> : 데이터 조회 &amp; 검색</li>
<li><code>INSERT</code> : 데이터 추가 ( 새로운 행 추가 )</li>
<li><code>UPDATE</code> : 데이터 수정</li>
<li><code>DELETE</code> : 데이터 삭제</li>
</ol>
<h3 id="■-ddl">■ DDL</h3>
<p>( Data Definition Language ) - 데이터 정의 언어</p>
<ol>
<li><code>CREATE</code> : 테이블 생성</li>
<li><code>ALTER</code> : 테이블 변경</li>
<li><code>DROP</code> : 테이블 삭제</li>
<li><code>RENAME</code> : 테이블 이름변경</li>
</ol>
<h3 id="■-dcl">■ DCL</h3>
<p>( Data Control Language ) - 데이터 제어 언어</p>
<ol>
<li><code>GRANT</code> : DB 접근 권한 부여</li>
<li><code>REVOKE</code> : DB 접근 권한 회수</li>
</ol>
<h3 id="■-tcl">■ TCL</h3>
<p>( Transaction Control Language ) - 트랜잭션 제어 언어
논리적인 작업의 단위를 묶어서 DML 에 의해 조작된 결과를 작업단위(트랜잭션) 별로 제어하는 명령어</p>
<ol>
<li><code>COMMIT</code> : 트랜잭션 실행</li>
<li><code>ROLLBACK</code> : 트랜잭션 취소</li>
<li><code>SAVEPOINT</code> : 롤백 지점을 설정</li>
</ol>
<hr>
<h2 id="mvc">MVC</h2>
<p>( Model - View - Controller )</p>
<ul>
<li><p>사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴</p>
</li>
<li><p>유지보수를 독립적으로 수행가능하며 중복 코딩의 문제점을 제거함</p>
</li>
<li><blockquote>
<p>데이터&amp;비즈니스 요건 변경 : <code>Model</code> 수정</p>
</blockquote>
</li>
<li><blockquote>
<p>화면의 변경 : <code>View</code> 수정</p>
</blockquote>
</li>
<li><blockquote>
<p>뷰&amp;모델 변경 : <code>Controller</code> 수정</p>
</blockquote>
</li>
<li><p>복잡한 대규모 프로그램의 경우 다수의 뷰와 모델이 컨트롤러를 통해 연결되기 때문에 컨트롤러가 불필요하게 커짐</p>
</li>
<li><blockquote>
<p>보완을 위해 다양한 패턴이 파생됨
( MVP , MVVM , Flux , Redux , RxMVVM 등 )</p>
</blockquote>
</li>
</ul>
<h3 id="■-model">■ Model</h3>
<p>애플리케이션의 정보, 데이터를 나타냄</p>
<ul>
<li>클라이언트가 편집하길 원하는 모든 데이터를 가지고 있어야 함</li>
<li>뷰나 컨트롤러에 대한 어떤 정보도 가지고 있지 않아야 함</li>
<li>변경이 일어나면, 변경 통지에 대한 처리방법을 구현해야 함</li>
</ul>
<h3 id="■-view">■ View</h3>
<p>데이터를 기반으로 클라이언트가 볼 수 있는 화면</p>
<ul>
<li>모델이 가지고 있는 정보를 따로 저장되어있으면 안 됨</li>
<li>모델이나 컨트롤러와 같이 다른 구성요소들을 몰라야 함</li>
<li>변경이 일어나면, 변경 통지에 대한 처리방법을 구현해야 함</li>
</ul>
<h3 id="■-controller">■ Controller</h3>
<p>사용자로부터의 입력에 대한 응답으로 모델 및 뷰를 업데이트함</p>
<ul>
<li>모델이나 뷰에 대해 알고 있어야 함</li>
<li>모델이나 뷰의 변경을 모니터링 해야 함</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring - Lv.3 과제]]></title>
            <link>https://velog.io/@jilog_94/Spring-Lv.3-%EA%B3%BC%EC%A0%9C</link>
            <guid>https://velog.io/@jilog_94/Spring-Lv.3-%EA%B3%BC%EC%A0%9C</guid>
            <pubDate>Mon, 24 Apr 2023 13:27:41 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-04-24">2023-04-24</h1>
<hr>
<h2 id="api-명세서--요구사항">API 명세서 &amp; 요구사항</h2>
<p><a href="https://www.notion.so/3-9a1dc18636664d50afe3f119b2e7927d">Spring Lv.3 API 명세서 &amp; 요구사항</a></p>
<hr>
<h2 id="폴더-구조">폴더 구조</h2>
<p><img src="https://velog.velcdn.com/images/jilog_94/post/f70b4b66-9543-4496-a990-319bae9ff126/image.png" alt=""></p>
<hr>
<h2 id="역경과-고난">역경과 고난</h2>
<p>1. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[WIL - 3주차 정리]]></title>
            <link>https://velog.io/@jilog_94/WIL-3%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jilog_94/WIL-3%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 23 Apr 2023 12:41:02 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-04-23">2023-04-23</h1>
<hr>
<h1 id="ioc">IoC</h1>
<p>( Inversion of Control ) - 제어의 역전</p>
<ul>
<li>메서드나 객체의 호출작업을 개발자가 결정하는 것이 아니라, 외부에서 결정되는 것</li>
</ul>
<h2 id="장점">장점</h2>
<ol>
<li>결합도가 줄어듦</li>
<li>유연선이 높아짐</li>
<li>가독성이 높아짐</li>
<li>코드 중복이 줄어듦</li>
<li>유지 보수에 편리함</li>
</ol>
<hr>
<h1 id="di">DI</h1>
<p>( Dependency Injection ) - 의존성 주입</p>
<ul>
<li>외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴
( IoC 프로그래밍 모델을 구현하는 방식 중 하나 )</li>
<li>인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입함</li>
</ul>
<h2 id="의존관계">의존관계</h2>
<p>의존 대상 B가 변하면, 그것이 A에 영향을 미칠 때 A는 B와 의존관계라고 함</p>
<h4 id="■-di-가-필요한-이유">■ DI 가 필요한 이유</h4>
<ol>
<li>클래스와 클래스 간의 결합이 강하면 하나의 클래스가 바뀌면 매번 생성자를 바꿔줘야 하는 등 유연성이 떨어지게 됨</li>
<li>객체 지향 프로그래밍을 위해선 클래스 간의 관계에 의존하면 안되고 객체들 간의 관계를 맺어야 함</li>
</ol>
<h2 id="주입-방법">주입 방법</h2>
<h3 id="생성자-주입">생성자 주입</h3>
<ul>
<li>생성자를 만들어 의존 관계를 주입하는 것</li>
<li>주입받은 객체가 변하지 않거나, 반드시 객체의 주입이 필요한 경우 사용</li>
</ul>
<h3 id="수정자-주입">수정자 주입</h3>
<ul>
<li>@Setter 어노테이션을 사용해 의존 관계를 주입하는 것</li>
<li>주입받는 객체가 변경될 가능성이 있는 경우 사용</li>
<li>런타임에서 의존성을 주입함</li>
</ul>
<h3 id="필드-주입">필드 주입</h3>
<ul>
<li>@Autowired 어노테이션을 사용해 의존 관계를 주입하는 것</li>
<li>런타임에서 의존성을 주입함</li>
</ul>
<h4 id="■-생성자-주입-방법을-권장함">■ 생성자 주입 방법을 권장함</h4>
<ol>
<li>NullPointerException 의 발생을 막음
객체가 생성되는 시점에 빈을 주입함. 생성시에 의존성 없이는 생성 불가능하기 때문에 일부러 null 을 주입하지 않는 이상 발생하지 않음</li>
<li>불변성을 활용할 수 있음
final 선언 가능</li>
<li>SRP (단일 책임 원칙) 를 지킬 수 있도록 유도함</li>
</ol>
<hr>
<h1 id="bean">Bean</h1>
<ul>
<li>Spring Ioc 컨테이너가 관리하는 자바 객체</li>
</ul>
<h2 id="등록-방법">등록 방법</h2>
<ol>
<li>어노테이션 ( Annotation ) 사용
<code>@Component</code> 어노테이션을 사용하거나,
스테레오 타입인 <code>@Controller</code> , <code>@Service</code> , <code>@Repository</code> 등을 사용함</li>
<li>Bean 설정 파일에 직접 등록
<code>@Configuration</code> , <code>@Bean</code> 어노테이션 사용함
<code>@Configuration</code> : 해당 파일에 빈을 등록하겠다는 선언</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring - JPA]]></title>
            <link>https://velog.io/@jilog_94/Spring-JPA</link>
            <guid>https://velog.io/@jilog_94/Spring-JPA</guid>
            <pubDate>Fri, 21 Apr 2023 04:13:08 GMT</pubDate>
            <description><![CDATA[<h1 id="jpa">JPA</h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring - Lv.2 과제]]></title>
            <link>https://velog.io/@jilog_94/Spring-Lv-2-%EA%B3%BC%EC%A0%9C</link>
            <guid>https://velog.io/@jilog_94/Spring-Lv-2-%EA%B3%BC%EC%A0%9C</guid>
            <pubDate>Thu, 20 Apr 2023 05:28:19 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-04-18--2023-04-23">2023-04-18 ~ 2023-04-23</h1>
<hr>
<h2 id="요구사항">요구사항</h2>
<ol>
<li>회원가입 API<ul>
<li><code>username</code> ,<code>password</code> 전달 받은 후 DB에 중복된 username이 없다면 회원 저장</li>
<li><code>username</code> : 최소 4자 이상, 10자 이하이며 알파벳 소문자(a<del>z), 숫자(0</del>9)</li>
<li><code>password</code> : 최소 8자 이상, 15자 이하이며 알파벳 대소문자(a<del>z, A</del>Z), 숫자(0~9)</li>
</ul>
</li>
<li>로그인 API<ul>
<li>username, password 전달 받은 후 password 비교</li>
<li>발급한 토큰을 Header에 추가하여 로그인</li>
</ul>
</li>
<li>전체 게시글 목록 조회 API<ul>
<li>제목, 작성자명(username), 작성내용, 작성날짜 조회</li>
<li>작성날짜 기준 내림차순 정리</li>
</ul>
</li>
<li>게시글 작성 API<ul>
<li>토큰 검사하여 유효한 토큰일 경우에만 작성 가능</li>
<li>제목, 작성내용 저장</li>
</ul>
</li>
<li>선택한 게시글 조회 API<ul>
<li>선택한 게시글의 제목, 작성자명(username), 작성날짜, 작성내용 조회</li>
</ul>
</li>
<li>선택한 게시글 수정 API<ul>
<li>토큰 검사하여 유효한 토큰일 경우에만 수정 가능</li>
<li>제목, 작성내용 수정</li>
</ul>
</li>
<li>선택한 게시글 삭제 API<ul>
<li>토큰 검사하여 유효한 토큰일 경우에만 삭제 가능</li>
</ul>
</li>
</ol>
<hr>
<h2 id="api-명세서">API 명세서</h2>
<h3 id="■-회원가입">■ 회원가입</h3>
<ul>
<li>Method : POST</li>
<li>URL : /api/user/signup</li>
<li>Request<pre><code>{
  &quot;username&quot;:&quot;asdf12&quot;,
  &quot;password&quot;:&quot;asdf1234&quot;
}</code></pre></li>
<li>Response<pre><code>{
  &quot;message&quot;: &quot;회원가입 성공!&quot;,
  &quot;data&quot;: null
}</code></pre></li>
</ul>
<h3 id="■-로그인">■ 로그인</h3>
<ul>
<li>Method : POST</li>
<li>URL : /api/user/login</li>
<li>Request<pre><code>{
  &quot;username&quot;:&quot;asdf12&quot;,
  &quot;password&quot;:&quot;asdf1234&quot;
}</code></pre></li>
<li>Response<pre><code>{
  &quot;message&quot;: &quot;로그인 성공!&quot;,
  &quot;data&quot;: null
}</code></pre></li>
</ul>
<hr>
<h2 id="폴더-구조">폴더 구조</h2>
<p><img src="https://velog.velcdn.com/images/jilog_94/post/17e99f1f-0065-4cee-a796-a878f754e481/image.png" alt=""></p>
<hr>
<h2 id="전체적인-패키지-및-파일">전체적인 패키지 및 파일</h2>
<h3 id="■-controller">■ controller</h3>
<h4 id="▲-postcontroller">▲ PostController</h4>
<pre><code>package com.sparta.spring_post.controller;

import com.sparta.spring_post.dto.PostRequestDto;
import com.sparta.spring_post.dto.ResponseDto;
import com.sparta.spring_post.entity.Post;
import com.sparta.spring_post.service.PostService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping(&quot;/api&quot;)
public class PostController {

    // PostService 연결
    private final PostService postService;

    // 목록 조회
    @GetMapping(&quot;/posts&quot;)
    public ResponseDto&lt;List&lt;Post&gt;&gt; getAllPosts() {
        return postService.getAllPosts();
    }

    // 상세 조회
    @GetMapping(&quot;/posts/{id}&quot;)
    public ResponseDto&lt;Post&gt; getPost(@PathVariable Long id) {
        return postService.getPost(id);
    }

    // 추가
    @PostMapping(&quot;/post&quot;)
    public ResponseDto&lt;Post&gt; createPost(@RequestBody PostRequestDto postRequestDto, HttpServletRequest httpServletRequest) {
        return postService.createPost(postRequestDto, httpServletRequest);
    }

    // 수정
    @PutMapping(&quot;/post/{id}&quot;)
    public ResponseDto&lt;Post&gt; updatePost(@PathVariable Long id, @RequestBody PostRequestDto postRequestDto, HttpServletRequest httpServletRequest) {
        return postService.updatePost(id, postRequestDto, httpServletRequest);
    }

    // 삭제
    @DeleteMapping(&quot;/post/{id}&quot;)
    public ResponseDto deletePost(@PathVariable Long id, HttpServletRequest httpServletRequest) {
        return postService.deletePost(id, httpServletRequest);
    }

}</code></pre><h4 id="▲-usercontroller">▲ UserController</h4>
<pre><code>package com.sparta.spring_post.controller;

import com.sparta.spring_post.dto.LoginRequestDto;
import com.sparta.spring_post.dto.ResponseDto;
import com.sparta.spring_post.dto.SignupRequestDto;
import com.sparta.spring_post.service.UserService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping(&quot;/api/user&quot;)
public class UserController {

    // UserService 연결
    private final UserService userService;

    // 회원가입
    @PostMapping(&quot;/signup&quot;)
    public ResponseDto signup(@RequestBody SignupRequestDto signupRequestDto) {
        return userService.signup(signupRequestDto);
    }

    // 로그인
    @PostMapping(&quot;/login&quot;)
    public ResponseDto login(@RequestBody LoginRequestDto loginRequestDto, HttpServletResponse httpServletResponse) {
        return userService.login(loginRequestDto, httpServletResponse);
    }

}</code></pre><h3 id="■-dto">■ dto</h3>
<h4 id="▲-requestdto">▲ RequestDto</h4>
<pre><code>package com.sparta.spring_post.dto;

import lombok.Getter;

@Getter
public class SignupRequestDto {
    private String username;
    private String password;

}</code></pre><pre><code>package com.sparta.spring_post.dto;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class LoginRequestDto {
    private String username;
    private String password;

}</code></pre><h4 id="▲-responsedto">▲ ResponseDto</h4>
<pre><code>package com.sparta.spring_post.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor(staticName = &quot;set&quot;)
public class ResponseDto&lt;D&gt; {
    private String message;
    private D data;

    public static &lt;D&gt; ResponseDto&lt;D&gt; setSuccess(String message, D data) {
        return ResponseDto.set(message, data);
    }

    public static &lt;D&gt; ResponseDto&lt;D&gt; setFailed(String message) {
        return ResponseDto.set(message, null);
    }

}</code></pre><h3 id="■-entity">■ entity</h3>
<h4 id="▲-post">▲ Post</h4>
<pre><code>package com.sparta.spring_post.entity;

import com.sparta.spring_post.dto.PostRequestDto;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Entity
@NoArgsConstructor
public class Post extends Timestamped {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String content;

    @ManyToOne
    @JoinColumn(name = &quot;user_name&quot;, nullable = false)
    private Users users;

    public Post(Users users, PostRequestDto postRequestDto) {
        this.users = users;
        this.title = postRequestDto.getTitle();
        this.content = postRequestDto.getContent();
    }

    public void update(PostRequestDto postRequestDto) {
        this.title = postRequestDto.getTitle();
        this.content = postRequestDto.getContent();
    }

}</code></pre><h4 id="▲-timestamped">▲ Timestamped</h4>
<pre><code>package com.sparta.spring_post.entity;

import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class Timestamped {
    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime modifiedAt;

}</code></pre><h4 id="▲-users">▲ Users</h4>
<pre><code>package com.sparta.spring_post.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@Entity
public class Users {
    @Id
    @Column(name = &quot;user_name&quot;, nullable = false, unique = true)
    private String username;

    @Column(nullable = false)
    @JsonIgnore
    private String password;

    public Users(String username, String password) {
        this.username = username;
        this.password = password;
    }

}</code></pre><h3 id="■-jwt">■ jwt</h3>
<pre><code>package com.sparta.spring_post.jwt;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.security.Key;
import java.util.Base64;
import java.util.Date;

@Slf4j
@Component
@RequiredArgsConstructor
public class JwtUtil {

    public static final String AUTHORIZATION_HEADER = &quot;Authorization&quot;;
//    public static final String AUTHORIZATION_KEY = &quot;auth&quot;;
    private static final String BEARER_PREFIX = &quot;Bearer &quot;;
    private static final long TOKEN_TIME = 60 * 60 * 1000L;

    @Value(&quot;${jwt.secret.key}&quot;)
    private String secretKey;
    private Key key;
    private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

    @PostConstruct
    public void init() {
        byte[] bytes = Base64.getDecoder().decode(secretKey);
        key = Keys.hmacShaKeyFor(bytes);
    }

    // header 토큰을 가져오기
    public String resolveToken(HttpServletRequest request) {
        String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
        if (StringUtils.hasText(bearerToken) &amp;&amp; bearerToken.startsWith(BEARER_PREFIX)) {
            return bearerToken.substring(7);
        }
        return null;
    }

    // 토큰 생성
    public String createToken(String username) {
        Date date = new Date();

        return BEARER_PREFIX +
                Jwts.builder()
                        .setSubject(username)
                        .setExpiration(new Date(date.getTime() + TOKEN_TIME))
                        .setIssuedAt(date)
                        .signWith(key, signatureAlgorithm)
                        .compact();
    }

    // 토큰 검증
    public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
            return true;
        } catch (SecurityException | MalformedJwtException e) {
            log.info(&quot;Invalid JWT signature, 유효하지 않는 JWT 서명 입니다.&quot;);
        } catch (ExpiredJwtException e) {
            log.info(&quot;Expired JWT token, 만료된 JWT token 입니다.&quot;);
        } catch (UnsupportedJwtException e) {
            log.info(&quot;Unsupported JWT token, 지원되지 않는 JWT 토큰 입니다.&quot;);
        } catch (IllegalArgumentException e) {
            log.info(&quot;JWT claims is empty, 잘못된 JWT 토큰 입니다.&quot;);
        }
        return false;
    }

    // 토큰에서 사용자 정보 가져오기
    public Claims getUserInfoFromToken(String token) {
        return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
    }

}</code></pre><h3 id="■-repository">■ repository</h3>
<h4 id="▲-postrepository">▲ PostRepository</h4>
<pre><code>package com.sparta.spring_post.repository;

import com.sparta.spring_post.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface PostRepository extends JpaRepository&lt;Post, Long&gt; {
    List&lt;Post&gt; findAllByOrderByCreatedAtDesc();

}</code></pre><h4 id="▲-userrepository">▲ UserRepository</h4>
<pre><code>package com.sparta.spring_post.repository;

import com.sparta.spring_post.entity.Users;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserRepository extends JpaRepository&lt;Users, Long&gt; {
    Optional&lt;Users&gt; findByUsername(String username);

}</code></pre><h3 id="■-service">■ service</h3>
<h4 id="▲-postservice">▲ PostService</h4>
<pre><code>package com.sparta.spring_post.service;

import com.sparta.spring_post.dto.PostRequestDto;
import com.sparta.spring_post.dto.ResponseDto;
import com.sparta.spring_post.entity.Post;
import com.sparta.spring_post.entity.Users;
import com.sparta.spring_post.jwt.JwtUtil;
import com.sparta.spring_post.repository.PostRepository;
import com.sparta.spring_post.repository.UserRepository;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@RequiredArgsConstructor
public class PostService {

    // PostRepository 연결
    private final PostRepository postRepository;
    // UserRepository 연결
    private final UserRepository userRepository;
    // JwtUtil 연결
    private final JwtUtil jwtUtil;

    // 목록 조회
    @Transactional(readOnly = true)
    public ResponseDto&lt;List&lt;Post&gt;&gt; getAllPosts() {
        List&lt;Post&gt; posts = postRepository.findAllByOrderByCreatedAtDesc();
        return ResponseDto.setSuccess(&quot;게시물 목록 조회 성공!&quot;, posts);
    }

    // 상세 조회
    @Transactional(readOnly = true)
    public ResponseDto&lt;Post&gt; getPost(Long id) {
        Post post = postRepository.findById(id).orElseThrow(
                () -&gt; new IllegalArgumentException(id + &quot;번 게시물이 존재하지 않습니다.&quot;)
        );
        return ResponseDto.setSuccess(id + &quot;번 게시물 조회 성공!&quot;, post);
    }

    // 추가
    @Transactional
    public ResponseDto&lt;Post&gt; createPost(PostRequestDto postRequestDto, HttpServletRequest httpServletRequest) {
        String token = jwtUtil.resolveToken(httpServletRequest);

        if (token == null) {
            return ResponseDto.setFailed(&quot;토큰이 없습니다.&quot;);
        }

        try {
            jwtUtil.validateToken(token);
        } catch (Exception e) {
            return ResponseDto.setFailed(&quot;유효한 토큰이 없습니다.&quot;);
        }

        Users user = userRepository.findByUsername(postRequestDto.getUsername()).orElseThrow();

        Post post = new Post(user, postRequestDto);
        postRepository.save(post);
        return ResponseDto.setSuccess(&quot;게시물 작성 성공!&quot;, post);
    }

    // 수정
    @Transactional
    public ResponseDto&lt;Post&gt; updatePost(Long id, PostRequestDto postRequestDto, HttpServletRequest httpServletRequest) {
        String token = jwtUtil.resolveToken(httpServletRequest);
        Claims claims;

        Post post = postRepository.findById(id).orElseThrow(
                () -&gt; new IllegalArgumentException(id + &quot;번 게시물이 없습니다.&quot;)
        );

        if (token == null) {
            return ResponseDto.setFailed(&quot;토큰이 없습니다.&quot;);
        }

        try {
            jwtUtil.validateToken(token);
        } catch (Exception e) {
            return ResponseDto.setFailed(&quot;유효한 토큰이 없습니다.&quot;);
        }

        claims = jwtUtil.getUserInfoFromToken(token);
        if (post.getUsers().getUsername().equals(claims.getSubject())) {
            post.update(postRequestDto);
            return ResponseDto.setSuccess(id + &quot;번 게시물 수정 성공!&quot;, post);
        } else {
            return ResponseDto.setFailed(id + &quot;번 게시물을 수정할 권한이 없습니다.&quot;);
        }
    }

    // 삭제
    @Transactional
    public ResponseDto deletePost(Long id, HttpServletRequest httpServletRequest) {
        String token = jwtUtil.resolveToken(httpServletRequest);
        Claims claims;

        Post post = postRepository.findById(id).orElseThrow(
                () -&gt; new IllegalArgumentException(id + &quot;번 게시물이 없습니다.&quot;)
        );

        if (token == null) {
            return ResponseDto.setFailed(&quot;토큰이 없습니다.&quot;);
        }

        try {
            jwtUtil.validateToken(token);
        } catch (Exception e) {
            return ResponseDto.setFailed(&quot;유효한 토큰이 없습니다.&quot;);
        }

        claims = jwtUtil.getUserInfoFromToken(token);
        if (post.getUsers().getUsername().equals(claims.getSubject())) {
            postRepository.deleteById(id);
            return ResponseDto.setSuccess(id + &quot;번 게시물 삭제 성공!&quot;, null);
        } else {
            return ResponseDto.setFailed(id + &quot;번 게시물을 삭제할 권한이 없습니다.&quot;);
        }
    }

}</code></pre><h4 id="▲-userservice">▲ UserService</h4>
<pre><code>package com.sparta.spring_post.service;

import com.sparta.spring_post.dto.LoginRequestDto;
import com.sparta.spring_post.dto.ResponseDto;
import com.sparta.spring_post.dto.SignupRequestDto;
import com.sparta.spring_post.entity.Users;
import com.sparta.spring_post.jwt.JwtUtil;
import com.sparta.spring_post.repository.UserRepository;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;
import java.util.regex.Pattern;

@Service
@RequiredArgsConstructor
public class UserService {

    // UserRepository 연결
    private final UserRepository userRepository;
    // JwtUtil 연결
    private final JwtUtil jwtUtil;

    @Transactional
    public ResponseDto signup(SignupRequestDto signupRequestDto) {
        String username = signupRequestDto.getUsername();
        String password = signupRequestDto.getPassword();

        // 아이디 형식 확인
        if (!Pattern.matches(&quot;^[a-z0-9]{4,10}$&quot;, username)) {
            return ResponseDto.setFailed(&quot;형식에 맞지 않는 아이디 입니다.&quot;);
        }

        // 비밀번호 형식 확인
        if (!Pattern.matches(&quot;^[a-zA-Z0-9]{8,15}$&quot;, password)) {
            return ResponseDto.setFailed(&quot;형식에 맞지 않는 비밀번호 입니다.&quot;);
        }

        // 회원 중복 확인
        Optional&lt;Users&gt; found = userRepository.findByUsername(username);
        if (found.isPresent()) {
            return ResponseDto.setFailed(&quot;중복된 사용자입니다.&quot;);
        }

        Users users = new Users(username, password);
        userRepository.save(users);
        return ResponseDto.setSuccess(&quot;회원가입 성공!&quot;, null);
    }

    @Transactional(readOnly = true)
    public ResponseDto login(LoginRequestDto loginRequestDto, HttpServletResponse httpServletResponse) {
        String username = loginRequestDto.getUsername();
        String password = loginRequestDto.getPassword();

        // 아이디 확인
        Users users = userRepository.findByUsername(username).orElseThrow(
                () -&gt; new IllegalArgumentException(&quot;존재하지 않는 아이디입니다.&quot;)
        );

        // 비밀번호 확인
        if (!users.getPassword().equals(password)) {
            return ResponseDto.setFailed(&quot;일치하지 않는 비밀번호 입니다.&quot;);
        }

        httpServletResponse.addHeader(JwtUtil.AUTHORIZATION_HEADER, jwtUtil.createToken(users.getUsername()));
        return ResponseDto.setSuccess(&quot;로그인 성공!&quot;, null);
    }

}</code></pre><hr>
<h2 id="역경과-고난">역경과 고난</h2>
<ol>
<li><p>JWT가 너무 이해 안가서 3,4일 정도 다음 레벨 과제를 진행하지 않고 이해하는 시간을 가졌다.
JWT ( Json Web Token ) 은 말그대로 웹에서 사용되는 JSON 형식의 토큰에 대한 표준 규격인데 주로 클라이언트의 인증 또는 인가 정보를 서버와 클라이언트 간에 안전하게 주고 받기 위해 사용된다.
Token 은 <code>header</code> , <code>payload</code> , <code>signature</code> 로 구분되어 표현되는데
<code>header</code> : 토큰의 타입 &amp; 해싱 알고리즘 정보,
<code>payload</code> : 토큰에 담을 정보 ( claim ),
<code>signature</code> : 비밀키
가 포함된다.</p>
</li>
<li><p>Servlet 도 이해가 안가는데 음.. 이건 공부가 더 필요하다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL - Spring 입문(2)]]></title>
            <link>https://velog.io/@jilog_94/TIL-Spring-%EC%9E%85%EB%AC%B82</link>
            <guid>https://velog.io/@jilog_94/TIL-Spring-%EC%9E%85%EB%AC%B82</guid>
            <pubDate>Thu, 20 Apr 2023 05:27:01 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-04-20">2023-04-20</h1>
<hr>
<h1 id="ip주소">IP주소</h1>
<p>네트워크망에서 각자의 컴퓨터(노드)를 식별하기 위한 위치 주소
<code>192.168.0.123</code> 와 같이 생긴 숫자
-&gt; 실제로는 32자리의 2진수로 이뤄져있음 ( 8비트인 각각의 영역을 &#39;.&#39;으로 구분 )
( 00000000.00000000.00000000.00000000 ~ 11111111.11111111.11111111.11111111 )</p>
<pre><code>192.168.0.123
└───┬────┘└─┬─┘
 네트워크 호스트
   주소   주소</code></pre><ul>
<li>네트워크 주소 : 공통적인 부분</li>
<li>호스트 주소 : 중복이 없고 유일한 식별자 역할
( 하나의 네트워크 상에 여러 호스트 주소가 있을 수 있음 )</li>
</ul>
<hr>
<h1 id="브라우저">브라우저</h1>
<p>( browser )
인터넷에서 웹 서버의 모든 정보를 볼 수 있도록 하고, 문서 검색을 도와주는 응용프로그램
( 네이버나 구글 같은 사이트에 접속할 수 있는 도구 )
<code>Google Chrome</code> , <code>Apple Safari</code> , <code>Naver Whale</code>, <code>Microsoft Edge</code> 등</p>
<hr>
<h1 id="dns">DNS</h1>
<p>( Domain Name System )
웹사이트의 IP주소와 도메인 주소를 이어주는 시스템
( 도메인 주소를 사용했을 때 입력한 도메인을 실제 네트워크상에서 사용하는 IP주소로 바꾸고 해당 IP주소로 접속하는 과정이 필요함. 이 과정, 전체 시스템을 DNS라고 함 )
-&gt; 길고 복잡한 IP주소를 외울 수 없기 때문에 사용함</p>
<p>역트리 구조로 최상위 루트(Root)부터 Top-Level Domain, Second-Level Domain, Third-Level Domain을 단계적으로 찾음</p>
<pre><code>www.naver.com.
&lt;-------------
뒤에서부터 찾음</code></pre><ul>
<li><code>.</code> : 맨 마지막에 붙은 .은 Root로서 생략함</li>
<li><code>com</code> : Top-Level Domain ( TLD )</li>
<li><code>naver</code> : Second-Level Domain</li>
<li><code>www</code> : Third-Level Domain</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jilog_94/post/a5b27c6f-8910-486c-8765-958961bc2ac4/image.png" alt=""><a href="https://dev.dwer.kr/2020/03/dns-master-slave.html">( 이미지 출처 )</a></p>
<ul>
<li><p><code>Local DNS</code> ( 기지국 DNS )
기본적으로 인터넷을 사용하기 위해선 IP를 할당해주는 통신사(KT, SK, LG 등)에 등록을 해야 함
인터넷에 연결되면 가입한 각 통신사의 기지국 DNS 서버가 자동으로 등록됨</p>
</li>
<li><p><code>Root DNS</code> ( 루트 네임서버 )
ICANN( 국제인터넷주소관리기구 )이 직접 관리하는 절대 존엄 서버
TLD DNS 서버 IP들을 저장해두고 안내하는 역할을 함</p>
</li>
<li><p><code>TLD DNS Server</code> ( 최상위 도메인 서버 )
도메인 등록 기관이 관리하는 서버
도메인의 가장 마지막 부분( .com , .co.kr 등 )을 관리하고 부여하는 서버
Authoritative DNS 서버 주소를 저장해두고 안내하는 역할</p>
</li>
<li><p><code>Authoritative DNS Server</code> ( 권한 )
실제 개인 도메인과 IP주소의 관계가 기록, 저장, 변경되는 서버</p>
</li>
</ul>
<hr>
<h1 id="http">HTTP</h1>
<p>( HyperText Transfer Protocol )
데이터를 주고 받는 양식을 정의한 <code>정해둔 약속</code> , <code>통신 규약</code>
HTTP에서는 언제나 Request(요청), Response(응답)라는 개념이 존재함
<img src="https://velog.velcdn.com/images/jilog_94/post/5c227e5e-d263-430b-a17c-b74de80ec86a/image.png" alt="">( 이미지 출처 : 항해99 )</p>
<h2 id="http-구성요소">HTTP 구성요소</h2>
<h3 id="■-method">■ Method</h3>
<p>( 호출 / 요청 방식 )</p>
<ul>
<li>GET : 조회</li>
<li>POST : 생성</li>
<li>PUT : 변경</li>
<li>DELETE : 삭제</li>
</ul>
<h3 id="■-header">■ Header</h3>
<p>( 추가 데이터, 메타 데이터 )
다양한 의사 표현을 위한 데이터를 모두 포함하고 있으며 <code>Method</code> 도 <code>Header</code> 에 포함됨</p>
<h3 id="■-payload">■ Payload</h3>
<p>( 실제 데이터 )
응답 : 서버가 응답을 보낼 때는 항상 Payload를 보낼 수 있음
요청 : 클라이언트가 요청을 할 때는 GET method 를 제외한 요청일 때 payload를 보낼 수 있음</p>
<h2 id="restful-api">RESTful API</h2>
<p>( Representational State Transfer )
서버 api가 적절하게 http를 준수하며 잘 설계되어있음</p>
<hr>
<h1 id="spring">Spring</h1>
<p>Java 애플리케이션 개발을 편하게 할 수 있게 해주는 오픈소스 프레임워크</p>
<h1 id="springboot">SpringBoot</h1>
<p>스프링으로 애플리케이션을 만들 때에 필요한 설정을 간편하게 처리해주는 별도의 프레임워크</p>
<hr>
<h1 id="레이어드-아키텍처-패턴">레이어드 아키텍처 패턴</h1>
<p>( Layered Architecture Pattern = Multi-tier Architecture Pattern )
백엔드 API코드에 가장 널리 적용되는 패턴 중 하나로서,
코드를 논리적인 부분 혹은 역할에 따라 독립된 모듈로 나누어서 구성하는 패턴
<img src="https://velog.velcdn.com/images/jilog_94/post/e641ba6a-6939-416f-a1eb-e726c4fc9e6f/image.png" alt=""><a href="https://cat-minzzi.tistory.com/74">( 이미지 출처 )</a></p>
<h3 id="■-presentation-layer">■ Presentation Layer</h3>
<ul>
<li>사용자와 상호 작용 처리 계층</li>
<li>MVC ( Model &amp; View &amp; Controller )가 속함</li>
<li><code>@Controller</code></li>
</ul>
<h3 id="■-business-layer">■ Business Layer</h3>
<p>( = Domain Layer = Service Layer )</p>
<ul>
<li>서비스 / 시스템의 핵심 로직</li>
<li>입력 / 저장된 데이터를 기반으로 계산해서 애플리케이션이 수행해야하는 도메인과 관련된 작업들을 담당함</li>
<li><code>@Service</code></li>
</ul>
<h3 id="■-persistence-layer">■ Persistence Layer</h3>
<p>( = Data Access Layer )</p>
<ul>
<li>DB 또는 원격 서비스에 영구 데이터를 관리하는 방법을 분류하는 데이터 접근 계층</li>
<li><code>@Repository</code></li>
</ul>
<hr>
<h2 id="orm">ORM</h2>
<p>( Object Relational Mapping ) - 객체 관계 매핑
프로그래밍 언어의 객체와 관계형 데이터베이스의 데이터를 자동으로 매핑(연결)해주는 도구</p>
<h4 id="--사용-이유">- 사용 이유</h4>
<p>객체지향 프로그래밍은 클래스를 사용하고, 관계형 데이터베이스는 테이블을 사용하기 때문에 객체 모델과 관계형 모델간의 불일치가 존재함
-&gt; ORM을 통해 객체 간의 관계를 바탕으로 SQL을 자동으로 생성하여 불일치를 해결함
( 객체를 통해 간접적으로 DB를 다룸 )</p>
<h2 id="jpa">JPA</h2>
<p>( Java Persistence API )
ORM을 사용하기 위한 인터페이스의 모음</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring - Lv.1 과제]]></title>
            <link>https://velog.io/@jilog_94/Spring-LV-1-%EA%B3%BC%EC%A0%9C</link>
            <guid>https://velog.io/@jilog_94/Spring-LV-1-%EA%B3%BC%EC%A0%9C</guid>
            <pubDate>Mon, 17 Apr 2023 01:17:59 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-04-14--2023-04-17">2023-04-14 ~ 2023-04-17</h1>
<hr>
<h2 id="주의사항">주의사항</h2>
<ol>
<li>Entity를 그대로 반환하지 말고, Dto에 담아서 반환</li>
<li>JSON 반환하는 API형태</li>
<li>Postman 사용</li>
</ol>
<hr>
<h2 id="요구사항">요구사항</h2>
<ol>
<li>UseCase 그려보기</li>
<li>전체 게시글 목록 조회 API<ul>
<li>제목, 작성자명, 작성내용, 작성날짜 조회</li>
<li>작성날짜 기준 내림차순 정리</li>
</ul>
</li>
<li>게시글 작성 API<ul>
<li>제목, 작성자명, 비밀번호, 작성내용 저장</li>
</ul>
</li>
<li>선택한 게시글 조회 API<ul>
<li>선택한 게시글의 제목, 작성자명, 작성날짜, 작성내용 조회</li>
</ul>
</li>
<li>선택한 게시글 수정 API<ul>
<li>수정할 데이터와 비밀번호를 같이 보내서 서버에서 비밀번호 일치 여부 확인</li>
<li>제목, 작성자명, 작성내용 수정</li>
</ul>
</li>
<li>선택한 게시글 삭제 API<ul>
<li>비밀번호를 같이 보내서 서버에서 비밀번호 일치 여부 확인</li>
</ul>
</li>
</ol>
<hr>
<h2 id="api-명세서">API 명세서</h2>
<h3 id="■-전체-게시글-목록-조회">■ 전체 게시글 목록 조회</h3>
<ul>
<li>Method : GET</li>
<li>URL : /api/posts</li>
<li>Request : -</li>
<li>Response<pre><code>[
  {
      &quot;createdAt&quot;: &quot;2023-04-17T12:22:37.542175&quot;,
      &quot;modifiedAt&quot;: &quot;2023-04-17T12:22:37.542175&quot;,
      &quot;id&quot;: 3,
      &quot;author&quot;: &quot;11&quot;,
      &quot;title&quot;: &quot;11&quot;,
      &quot;content&quot;: &quot;11&quot;
  },
  {
      &quot;createdAt&quot;: &quot;2023-04-17T12:22:36.939707&quot;,
      &quot;modifiedAt&quot;: &quot;2023-04-17T12:22:36.939707&quot;,
      &quot;id&quot;: 2,
      &quot;author&quot;: &quot;11&quot;,
      &quot;title&quot;: &quot;11&quot;,
      &quot;content&quot;: &quot;11&quot;
  },
  {
      &quot;createdAt&quot;: &quot;2023-04-17T12:22:36.187211&quot;,
      &quot;modifiedAt&quot;: &quot;2023-04-17T12:22:36.187211&quot;,
      &quot;id&quot;: 1,
      &quot;author&quot;: &quot;11&quot;,
      &quot;title&quot;: &quot;11&quot;,
      &quot;content&quot;: &quot;11&quot;
  }
]</code></pre></li>
</ul>
<h3 id="■-선택한-게시글-조회">■ 선택한 게시글 조회</h3>
<ul>
<li>Method : GET</li>
<li>URL : /api/posts/{id}</li>
<li>Request : -</li>
<li>Response<pre><code>{
  &quot;createdAt&quot;: &quot;2023-04-17T12:22:36.187211&quot;,
  &quot;modifiedAt&quot;: &quot;2023-04-17T12:22:43.910917&quot;,
  &quot;id&quot;: 1,
  &quot;author&quot;: &quot;11&quot;,
  &quot;title&quot;: &quot;11&quot;,
  &quot;content&quot;: &quot;11&quot;
}</code></pre></li>
</ul>
<h3 id="■-게시글-작성">■ 게시글 작성</h3>
<ul>
<li>Method : POST</li>
<li>URL : /api/post</li>
<li>Request<pre><code>{
  &quot;author&quot;:&quot;11&quot;,
  &quot;password&quot;:&quot;11&quot;,
  &quot;title&quot;:&quot;11&quot;,
  &quot;content&quot;:&quot;11&quot;
}</code></pre></li>
<li>Response<pre><code>{
  &quot;createdAt&quot;: &quot;2023-04-17T12:22:37.5421747&quot;,
  &quot;modifiedAt&quot;: &quot;2023-04-17T12:22:37.5421747&quot;,
  &quot;id&quot;: 1,
  &quot;author&quot;: &quot;11&quot;,
  &quot;title&quot;: &quot;11&quot;,
  &quot;content&quot;: &quot;11&quot;
}</code></pre></li>
</ul>
<h3 id="■-선택한-게시글-수정">■ 선택한 게시글 수정</h3>
<ul>
<li>Method : PUT</li>
<li>URL : /api/post/{id}</li>
<li>Request<pre><code>{
  &quot;author&quot;:&quot;11&quot;,
  &quot;password&quot;:&quot;11&quot;,
  &quot;title&quot;:&quot;11 수정&quot;,
  &quot;content&quot;:&quot;11 수정&quot;
}</code></pre></li>
<li>Response<pre><code>{
  &quot;createdAt&quot;: &quot;2023-04-17T12:22:36.187211&quot;,
  &quot;modifiedAt&quot;: &quot;2023-04-17T12:22:36.187211&quot;,
  &quot;id&quot;: 1,
  &quot;author&quot;: &quot;11&quot;,
  &quot;title&quot;: &quot;11 수정&quot;,
  &quot;content&quot;: &quot;11 수정&quot;
}</code></pre></li>
</ul>
<h3 id="■-선택한-게시글-삭제">■ 선택한 게시글 삭제</h3>
<ul>
<li>Method : DELETE</li>
<li>URL : /api/post/{id}</li>
<li>Request<pre><code>{
  &quot;password&quot; :&quot;11&quot;
}</code></pre></li>
<li>Response<pre><code>성공적으로 삭제되었습니다.</code></pre></li>
</ul>
<hr>
<h2 id="폴더-구조">폴더 구조</h2>
<p><img src="https://velog.velcdn.com/images/jilog_94/post/66e27225-9f51-444a-a76c-0b5d7f9c2d49/image.png" alt=""></p>
<hr>
<h2 id="전체적인-패키지-및-파일">전체적인 패키지 및 파일</h2>
<h3 id="■-controller">■ controller</h3>
<pre><code>// Client &lt;-Dto-&gt; Controller &lt;-Dto-&gt; Service &lt;-Dto-&gt; Repository &lt;-Entity-&gt; DB
package com.sparta.spring_post.controller;

import com.sparta.spring_post.dto.PostRequestDto;
import com.sparta.spring_post.dto.PostResponseDto;
import com.sparta.spring_post.service.PostService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequiredArgsConstructor
public class PostController {

    // PostService 연결
    private final PostService postService;

    // 목록 조회
    @GetMapping(&quot;/api/posts&quot;)
    public List&lt;PostResponseDto&gt; getAllPosts() {
        return postService.getAllPosts();
    }

    // 상세 조회
    @GetMapping(&quot;/api/posts/{id}&quot;)
    public PostResponseDto getPost(@PathVariable Long id) {
        return postService.getPost(id);
    }

    // 추가
    @PostMapping(&quot;/api/post&quot;)
    public PostResponseDto createPost(@RequestBody PostRequestDto postRequestDto) {
        return postService.createPost(postRequestDto);
    }

    // 수정
    @PutMapping(&quot;/api/post/{id}&quot;)
    public PostResponseDto updatePost(@PathVariable Long id, @RequestBody PostRequestDto postRequestDto) {
        return postService.updatePost(id, postRequestDto);
    }

    // 삭제
    @DeleteMapping(&quot;/api/post/{id}&quot;)
    public String deletePost(@PathVariable Long id, @RequestParam(&quot;password&quot;) String password) {
        return postService.deletePost(id, password);
    }

}</code></pre><h3 id="■-dto">■ dto</h3>
<h4 id="▲-requestdto">▲ RequestDto</h4>
<pre><code>// Client &lt;-Dto-&gt; Controller &lt;-Dto-&gt; Service &lt;-Dto-&gt; Repository &lt;-Entity-&gt; DB
package com.sparta.spring_post.dto;

import com.sparta.spring_post.entity.Post;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class PostRequestDto {
    private String author;
    private String password;
    private String title;
    private String content;

    public Post toEntity() {
        return Post.builder()
                .author(author)
                .password(password)
                .title(title)
                .content(content)
                .build();
    }
}</code></pre><h4 id="▲-responsedto">▲ ResponseDto</h4>
<pre><code>// Client &lt;-Dto-&gt; Controller &lt;-Dto-&gt; Service &lt;-Dto-&gt; Repository &lt;-Entity-&gt; DB
package com.sparta.spring_post.dto;

import com.sparta.spring_post.entity.Post;
import com.sparta.spring_post.entity.Timestamped;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Getter
@NoArgsConstructor
public class PostResponseDto extends Timestamped {
    private LocalDateTime createdAt;
    private LocalDateTime modifiedAt;
    private Long id;
    private String author;
    private String title;
    private String content;

    public PostResponseDto(Post post) {
        this.createdAt = post.getCreatedAt();
        this.modifiedAt = post.getModifiedAt();
        this.id = post.getId();
        this.author = post.getAuthor();
        this.title = post.getTitle();
        this.content = post.getContent();
    }
}</code></pre><h3 id="■-entity">■ entity</h3>
<pre><code>// Client &lt;-Dto-&gt; Controller &lt;-Dto-&gt; Service &lt;-Dto-&gt; Repository &lt;-Entity-&gt; DB
package com.sparta.spring_post.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sparta.spring_post.dto.PostRequestDto;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Entity
@NoArgsConstructor
public class Post extends Timestamped {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false)
    private String author;

    @Column(nullable = false)
    @JsonIgnore // 데이터를 주고받을 때, 해당 데이터 ignore. 응답값 보이지 않음
    private String password;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String content;

    @Builder
    public Post(String author, String password, String title, String content) {
        this.author = author;
        this.password = password;
        this.title = title;
        this.content = content;
    }

    public void update(PostRequestDto postRequestDto) {
        this.author = postRequestDto.getAuthor();
        this.password = postRequestDto.getPassword();
        this.title = postRequestDto.getTitle();
        this.content = postRequestDto.getContent();
    }
}</code></pre><h4 id="▲-timstamped">▲ Timstamped</h4>
<pre><code>package com.sparta.spring_post.entity;

import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class Timestamped {

    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime modifiedAt;
}</code></pre><h3 id="■-repository">■ repository</h3>
<pre><code>// Client &lt;-Dto-&gt; Controller &lt;-Dto-&gt; Service &lt;-Dto-&gt; Repository &lt;-Entity-&gt; DB
package com.sparta.spring_post.repository;

import com.sparta.spring_post.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface PostRepository extends JpaRepository&lt;Post, Long&gt; {
    List&lt;Post&gt; findAllByOrderByModifiedAtDesc();
}</code></pre><h3 id="■-service">■ service</h3>
<pre><code>// Client &lt;-Dto-&gt; Controller &lt;-Dto-&gt; Service &lt;-Dto-&gt; Repository &lt;-Entity-&gt; DB
package com.sparta.spring_post.service;

import com.sparta.spring_post.dto.PostRequestDto;
import com.sparta.spring_post.dto.PostResponseDto;
import com.sparta.spring_post.entity.Post;
import com.sparta.spring_post.repository.PostRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class PostService {

    // PostRepository 연결
    private final PostRepository postRepository;

    // 목록 조회
    @Transactional(readOnly = true)
    public List&lt;PostResponseDto&gt; getAllPosts() {
        List&lt;Post&gt; posts = postRepository.findAllByOrderByModifiedAtDesc();
        List&lt;PostResponseDto&gt; dtos = new ArrayList&lt;&gt;();
        for (Post post : posts) {
            dtos.add(new PostResponseDto(post));
        }
        return dtos;
    }

    // 상세 조회
    @Transactional(readOnly = true)
    public PostResponseDto getPost(Long id) {
        Post post = postRepository.findById(id).orElseThrow();
        PostResponseDto dtos = new PostResponseDto(post);
        dtos.getClass();
        return dtos;
    }

    // 추가
    @Transactional
    public PostResponseDto createPost(PostRequestDto postRequestDto) {
        Post post = postRepository.save(postRequestDto.toEntity());
        return new  PostResponseDto(post);
    }

    // 수정
    @Transactional
    public PostResponseDto updatePost(Long id, PostRequestDto postRequestDto) {
        Post post = postRepository.findById(id).orElseThrow();
        PostResponseDto dtos = new PostResponseDto(post);
        if (!post.getPassword().equals(postRequestDto.getPassword())) {
            return dtos;
        }
        post.update(postRequestDto);
        return new PostResponseDto(post);
    }

    // 삭제
    @Transactional
    public String deletePost(Long id, String password) {
        Post post = postRepository.findById(id).orElseThrow();
        if (!post.getPassword().equals(password)) {
            return &quot;비밀번호가 일치하지 않습니다.&quot;;
        }
        postRepository.deleteById(id);
        return &quot;성공적으로 삭제되었습니다.&quot;;
    }

}</code></pre><hr>
<h2 id="역경과-고난">역경과 고난</h2>
<ol>
<li><p><code>Entity</code>를 그대로 반환하지 말고 <code>Dto</code>에 담아서 반환하라는 말의 의미를 처음에는 이해하지 못해서 그 말의 의미부터 구글링을 했다.
<code>Entity</code>는 실제 DB 테이블과 매핑되는 핵심 클래스이므로 Entity를 그대로 반환했을 경우 객체의 일관성, 안전성을 보장하기 어렵기 때문에 목적 자체가 전달인 <code>Dto</code>에 데이터를 담아서 반환해야한다.</p>
</li>
<li><p>처음엔 Dto를 RequestDto, ResponseDto 이렇게 둘로만 나누지 않고 CRUD별로 Dto를 나눴다. 그걸 본 기술매니저님이 그럴 필요없다 오히려 비효율적이다 라는 피드백을 주셔서 요청과 응답으로만 Dto를 다시 만들고 그걸 어떻게 적용해야하나 고민과 구글링의 연속이었다.</p>
</li>
<li><p>비밀번호같은 개인정보는 보안을 위해 데이터를 Response 해줄 때 나타나지 않도록 해야했는데 Request와 Response 둘의 정확한 쓰임새나 정의, 또 언제 어떻게 값을 담아서 무엇으로 응답을 해줘야하는지 너무 헷갈렸다. 그래서 일단 비밀번호까지 응답이 오도록 코드를 만든 다음 그것에 대해 고민을 해봤다. ResponseDto에서 password값을 포함하지 않도록 하면 되는 간단한 문제였고 또 그 후에 다시 찾아보니 Entity에서 애초에 <code>@JsonIgnore</code> 라고 선언을 해놓으면 그 값은 응답값이 보이지 않는다는 것을 알아냈다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[WIL - 2주차 정리]]></title>
            <link>https://velog.io/@jilog_94/WIL-2%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jilog_94/WIL-2%EC%A3%BC%EC%B0%A8-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 16 Apr 2023 12:27:16 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-04-16">2023-04-16</h1>
<hr>
<h1 id="http">HTTP</h1>
<p>( HyperText Transfer Protocol )
텍스트 기반의 통신 규약으로 인터넷에서 데이터를 주고받을 수 있는 프로토콜</p>
<ul>
<li>요청(request) : 클라이언트 -&gt; 서버</li>
<li>응답(responst) : 서버 -&gt; 클라이언트
<a href="https://velog.io/@surim014/HTTP%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80">https://velog.io/@surim014/HTTP%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</a></li>
</ul>
<h2 id="특징">특징</h2>
<ul>
<li>연결 상태를 유지하지 않는 비연결성 프로토콜임
(Cookie와 Session이 이 단점을 해결할 수 있음)</li>
<li>그렇기 때문에 요청-응답 방식으로 동작함</li>
</ul>
<h2 id="request">Request</h2>
<ul>
<li>GET</li>
<li>POST</li>
<li>PUT</li>
<li>DELETE</li>
</ul>
<h2 id="response">Response</h2>
<h3 id="상태-코드">상태 코드</h3>
<ul>
<li>1xx : 조건부 응답</li>
<li>2xx : 성공</li>
<li>3xx : 리다이렉션 완료</li>
<li>4xx : 요청 오류</li>
<li>5xx : 서버 오류</li>
</ul>
<hr>
<h1 id="https">HTTPS</h1>
<p>( HyperText Transfer Protocol Secure )
표준 HTTP와 동일한 방식으로 작동하지만 서버와 주고받는 데이터가 암호화되기 때문에 웹사이트에 추가적인 보호를 제공함</p>
<hr>
<h1 id="mvc">MVC</h1>
<p>( Model - View - Controller )
사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴
유지보수를 독립적으로 수행가능하며 중복 코딩의 문제점을 제거함</p>
<ul>
<li>model : 포함해야할 데이터가 무엇인지 정의함</li>
<li>view : 데이터를 보여주는 방식을 정의함</li>
<li>controller : 사용자로부터의 입력에 대한 응답으로 모델 및 뷰를 업데이트함</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL - Spring 입문(1)]]></title>
            <link>https://velog.io/@jilog_94/TIL-Spring-%EC%9E%85%EB%AC%B81</link>
            <guid>https://velog.io/@jilog_94/TIL-Spring-%EC%9E%85%EB%AC%B81</guid>
            <pubDate>Fri, 14 Apr 2023 00:55:45 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-04-14">2023-04-14</h1>
<hr>
<h1 id="mvc-패턴">MVC 패턴</h1>
<p>( Model - View - Controller )
<img src="https://velog.velcdn.com/images/jilog_94/post/9282f925-db82-4b6e-8cfe-e510237edc13/image.png" alt=""></p>
<ul>
<li>Model : DB와 연동하여 사용자가 입력한 데이터나 사용자에게 출력할 데이터를 다룸</li>
<li>View : 시각적으로 보여주는 부분</li>
<li>Controller : Model이 데이터를 어떻게 처리할지 알려주는 역할</li>
</ul>
<p>서로 분리하여 각자 맡은 역할에만 집중할 수 있도록 함</p>
<ul>
<li>유지보수 용이</li>
<li>확장성, 유연성 증가</li>
<li>중복코딩 방지</li>
</ul>
<hr>
<h1 id="패키지-구조">패키지 구조</h1>
<p><img src="https://velog.velcdn.com/images/jilog_94/post/6da7ad8e-79db-4607-932a-59cce9af7abb/image.png" alt=""></p>
<blockquote>
<p>Client &lt;-Dto-&gt; Controller &lt;-Dto-&gt; Service &lt;-Dto-&gt; Repository &lt;-Entity-&gt; DB</p>
</blockquote>
<h2 id="entity">Entity</h2>
<ul>
<li>DB의 테이블에 존재하는 Column들을 필드로 가지는 객체
테이블에 없는 칼럼을 필드로 가질 수 없음</li>
</ul>
<h2 id="dto">DTO</h2>
<p>( Data Transfer Object )</p>
<ul>
<li>데이터를 이동하기 위한 객체<h3 id="사용하는-이유">사용하는 이유</h3>
Entity 객체를 그대로 사용하지 않고 굳이 DTO를 사용하는 이유는</li>
</ul>
<ol>
<li>역할 분리</li>
<li>Entity 객체 데이터의 변질을 피하기 위함</li>
<li>View와 통신하는 DTO는 값이 추가되거나 삭제되는 변경 등이 많기 때문
등으로 정리할 수 있음</li>
</ol>
<h2 id="controller">Controller</h2>
<ul>
<li>Client의 요청을 DTO의 형태로 받아 Service의 기능을 호출하고, 적절한 응답을 DTO 형태로 반환하는 역할</li>
</ul>
<h2 id="service">Service</h2>
<ul>
<li>DTO를 통해 받은 데이터를 이용해 비즈니스 로직을 처리하고 Repository를 통해 DB에 접근하여 데이터를 관리하는 역할</li>
</ul>
<h2 id="repository">Repository</h2>
<ul>
<li>JPA를 사용하면 Repository를 통해 DB에 접근할 수 있음
Service와 DB를 연결해주는 역할</li>
</ul>
<h2 id="dao">DAO</h2>
<p>( Data Access Object )</p>
<ul>
<li>실제 DB에 접근하는 객체
JPA의 Repository와 비슷함</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[http 상태 코드]]></title>
            <link>https://velog.io/@jilog_94/http-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@jilog_94/http-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C</guid>
            <pubDate>Wed, 12 Apr 2023 13:39:40 GMT</pubDate>
            <description><![CDATA[<h1 id="http-상태-코드">http 상태 코드</h1>
<p><a href="https://tecoble.techcourse.co.kr/post/2020-08-31-http-status-code/">https://tecoble.techcourse.co.kr/post/2020-08-31-http-status-code/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java - 제네릭]]></title>
            <link>https://velog.io/@jilog_94/Java-%EC%A0%9C%EB%84%A4%EB%A6%AD</link>
            <guid>https://velog.io/@jilog_94/Java-%EC%A0%9C%EB%84%A4%EB%A6%AD</guid>
            <pubDate>Tue, 11 Apr 2023 00:09:52 GMT</pubDate>
            <description><![CDATA[<h1 id="제네릭">제네릭</h1>
<p>( Generic )
데이터의 타입(data type)을 일반화(generalize)하는 것
클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것</p>
<blockquote>
<p>어떤 자료구조를 만들어 배포하려고 할 때, String 타입도 지원하고 싶고 Integer 타입도 지원하고 싶고 많은 타입을 지원하고 싶다. 이럴 때 String 에 대한 클래스, Integer 에 대한 클래스 하나하나 만들면 너무 비효율적이기 때문에 제네릭(generic)을 사용한다.</p>
</blockquote>
<h3 id="장점">장점</h3>
<p>1) 잘못된 타입이 들어올 수 있는 것을 컴파일 단계에서 방지할 수 있음
2) 타입을 체크하고 변환해줄 필요가 없음 (관리 용이함)
3) 코드의 재사용성이 높아짐</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL - Java 기초(5)]]></title>
            <link>https://velog.io/@jilog_94/TIL-Java-%EA%B8%B0%EC%B4%885</link>
            <guid>https://velog.io/@jilog_94/TIL-Java-%EA%B8%B0%EC%B4%885</guid>
            <pubDate>Tue, 11 Apr 2023 00:08:31 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-04-11">2023-04-11</h1>
<hr>
<h1 id="생성자">생성자</h1>
<blockquote>
<p>객체가 생성될 때 호출되며 <code>객체를 초기화하는 역할</code>을 수행함</p>
</blockquote>
<pre><code>public Car() {}                // 선언
...
Car car = new Car();        // 호출</code></pre><ul>
<li>모든 클래스는 반드시 생성자가 하나 이상 존재함</li>
<li>생성자를 하나도 선언하지 않았다면 컴파일러가 기본 생성자를 자동으로 추가함</li>
<li>생성자가 하나라도 선언되어있다면 컴파일러는 기본 생성자를 추가하지 않음<pre><code>// 오버로딩 : 똑같은 메서드명을 사용하면서 매개변수의 종류에 따라 다른 기능을 수행하게 하는 것
// (1)
public Car(String modelName) {
  model = modelName;
  System.out.println(&quot;첫 번째 생성자가 호출되었습니다.&quot;);
}
// (2)
public Car(String modelName, String colorName) {
  model = modelName;
  color = colorName;
  System.out.println(&quot;두 번째 생성자가 호출되었습니다.&quot;);
}
// (3)
public Car(String modelName, String colorName, double priceValue) {
  model = modelName;
  color = colorName;
  price = priceValue;
  System.out.println(&quot;세 번째 생성자가 호출되었습니다.&quot;);
}
...
// GV60 모델만 기본으로 선택
Car car2 = new Car(&quot;GV60&quot;);
System.out.println(&quot;car2.model = &quot; + car2.model + &quot;\n&quot;);
</code></pre></li>
</ul>
<p>// GV70 모델, 색상 Blue 만 기본으로 선택
Car car3 = new Car(&quot;GV70&quot;, &quot;Blue&quot;);
System.out.println(&quot;car3.model = &quot; + car3.model);
System.out.println(&quot;car3.color = &quot; + car3.color + &quot;\n&quot;);</p>
<p>// GV80 모델, 색상 Black, 가격 50000000 으로 완전하게 고정된 경우
Car car4 = new Car(&quot;GV80&quot;, &quot;Black&quot;, 50000000);
System.out.println(&quot;car4.model = &quot; + car4.model);
System.out.println(&quot;car4.color = &quot; + car4.color);
System.out.println(&quot;car4.price = &quot; + car4.price + &quot;\n&quot;);</p>
<p>//
첫 번째 생성자가 호출되었습니다.
car2.model = GV60</p>
<p>두 번째 생성자가 호출되었습니다.
car3.model = GV70
car3.color = Blue</p>
<p>세 번째 생성자가 호출되었습니다.
car4.model = GV80
car4.color = Black
car4.price = 5.0E7</p>
<pre><code>
---

# this
- 인스턴스 자신을 표현하는 키워드
- 객체 내부 멤버에 접근할 때 this 키워드가 필수는 아니지만 상황에 따라 필수가 될 수 있음

## this( )
- 인스턴스 자신의 생성자를 호출하는 키워드</code></pre><p>// (1)
public Car(String model) {
    this(model, &quot;Blue&quot;, 50000000);
}
// (2)
public Car(String model, String color) {
    this(model, color, 100000000);
}
// (3)
public Car(String model, String color, double price) {
    this.model = model;
    this.color = color;
    this.price = price;
}
// 리턴타입이 인스턴스 자신의 클래스 타입일 때
Car returnInstance() {
    return this;
}
...
// 모델을 변경하면서 만들 수 있고 색상 : Blue, 가격 50000000 고정
Car car1 = new Car(&quot;GV60&quot;);
System.out.println(&quot;car1.model = &quot; + car1.model);
System.out.println(&quot;car1.color = &quot; + car1.color);
System.out.println(&quot;car1.price = &quot; + car1.price + &quot;\n&quot;);</p>
<p>// 모델, 색상을 변경하면서 만들 수 있고 가격 100000000 고정
Car car2 = new Car(&quot;GV70&quot;, &quot;Red&quot;);
System.out.println(&quot;car2.model = &quot; + car2.model);
System.out.println(&quot;car2.color = &quot; + car2.color);
System.out.println(&quot;car2.price = &quot; + car2.price + &quot;\n&quot;);</p>
<p>// GV80 모델, 색상 Black, 가격 120000000 으로 완전하게 고정된 경우
Car car3 = new Car(&quot;GV80&quot;, &quot;Black&quot;, 120000000);
System.out.println(&quot;car3.model = &quot; + car3.model);
System.out.println(&quot;car3.color = &quot; + car3.color);
System.out.println(&quot;car3.price = &quot; + car3.price + &quot;\n&quot;);</p>
<p>// this 키워드를 통해 car3 인스턴스 자신을 반환 : car3.returnInstance() = 인스턴스의 주소
System.out.println(car3.returnInstance().model); // car3의 model
System.out.println(car3.returnInstance().color); // car3의 color
System.out.println(car3.returnInstance().price); // car3의 price</p>
<p>//
car1.model = GV60
car1.color = Blue
car1.price = 5.0E7</p>
<p>car2.model = GV70
car2.color = Red
car2.price = 1.0E8</p>
<p>car3.model = GV80
car3.color = Black
car3.price = 1.2E8</p>
<p>GV80
Black
1.2E8</p>
<pre><code>
---

# 접근 제어자
- 클래스 내부에 선언된 데이터를 보호하기 위해 사용함
1) `public` : 접근 제한이 전혀 없음
2) `protected` : 같은 패키지 내, 다른 패키지의 자손클래스에서 접근 가능
3) `(default)` : 같은 패키지 내에서만 접근 가능
4) `private` : 같은 클래스 내에서만 접근 가능

#### ■ 그 외 제어자
`static` , `final` , `abstract`

## Getter
- 외부에서 객체의 private 한 필드를 읽을 필요가 있을 때 getter 메서드를 사용함

## Setter
- 외부에서 객체의 private 한 필드를 저장/수정할 필요가 있을 때 Setter 메서드를 사용함

---

# 패키지
( package )
- 클래스의 일부분이면서 클래스를 식별해 주는 용도
- `package 상위패키지.하위패키지;`

# import
- 다른 패키지에 있는 클래스를 사용하기 위해 명시하는 키워드</code></pre><p>import week03.packageExample.pk1.Car;</p>
<p>public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        car.horn();
    }
}</p>
<pre><code>
---

# 상속
- `extends` 키워드 사용</code></pre><p>public class 자식클래스 extends 부모클래스 {
    ...
}</p>
<p>```</p>
<ul>
<li>부모 클래스에 새로운 필드와 메서드가 추가되면 자식 클래스는 이를 상속받아 사용할 수 있음</li>
<li>자식 클래스에 새로운 필드와 메서드가 추가되어도 부모 클래스는 영향을 받지 않음</li>
<li>Java에서는 다중 상속을 허용하지 않음 (클래스간의 관계가 너무 복잡해짐)</li>
<li>부모 클래스에서 final 키워드를 사용하여 선언한 클래스는 더 이상 상속할 수 없는 클래스가 됨</li>
<li>부모 클래스에서 final 키워들르 사용하여 선언한 메서드는 더 이상 오버라이딩할 수 없는 메서드가 됨</li>
</ul>
<h2 id="상속관계">상속관계</h2>
<p><code>~은 ~이다</code></p>
<h2 id="포함관계">포함관계</h2>
<p><code>~은 ~을 가지고 있다</code></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL - Java 기초(4)]]></title>
            <link>https://velog.io/@jilog_94/TIL-Java-%EA%B8%B0%EC%B4%884</link>
            <guid>https://velog.io/@jilog_94/TIL-Java-%EA%B8%B0%EC%B4%884</guid>
            <pubDate>Mon, 10 Apr 2023 02:33:12 GMT</pubDate>
            <description><![CDATA[<h1 id="2023-04-10">2023-04-10</h1>
<hr>
<h1 id="클래스">클래스</h1>
<p>(class)</p>
<ul>
<li>객체를 생성하기 위한 설계도
[ 구성 멤버 : 필드 , 생성자 , 메서드 ]</li>
</ul>
<blockquote>
<p> &lt; 클래스 만드는 순서 &gt;</p>
</blockquote>
<ol>
<li>클래스 선언</li>
<li>클래스 필드 정의</li>
<li>클래스 생성자 정의</li>
<li>클래스 메서드 정의</li>
</ol>
<h2 id="클래스-선언">클래스 선언</h2>
<pre><code>public class Car {

}</code></pre><h2 id="클래스-필드-정의">클래스 필드 정의</h2>
<h3 id="필드">필드</h3>
<ul>
<li>객체의 데이터를 저장하는 역할</li>
</ul>
<p>1) 고유 데이터 영역
2) 상태 데이터 영역
3) 객체 데이터 영역</p>
<pre><code>public class Car {
    // 1) 고유 데이터 영역
    String company;            // 자동차 회사
    String model;            // 자동차 모델
    String color;            // 자동차 색상
    double price;            // 자동차 가격
    // 2) 상태 데이터 영역
    double speed;            // 자동차 속도 (km/h)
    char gear;                // 기어의 상태 (P, R, N, D)
    boolean lights;            // 자동차 조명의 상태
    // 3) 객체 데이터 영역
    Tire tire;                // 타이어 클래스를 만든 후 적용
    Door door;                // 도어 클래스를 만든 후 적용
    Handle handle;            // 핸들 클래스를 만든 후 적용
}
public class Tire {
    public Tire() {}
}
public class Door {
    public Door() {}
}
public class Handle {
    public Handle() {}
}</code></pre><h2 id="클래스-생성자-정의">클래스 생성자 정의</h2>
<h3 id="생성자">생성자</h3>
<ul>
<li><p>처음 객체가 생성될 때 (instance화) 어떤 로직을 수행해야 하며, 어떤 값이 필수로 들어와야 하는지 정의</p>
<pre><code>public class Car {
  String company;            // 자동차 회사
  String model;            // 자동차 모델
  String color;            // 자동차 색상
  double price;            // 자동차 가격
  double speed;            // 자동차 속도 (km/h)
  char gear;                // 기어의 상태 (P, R, N, D)
  boolean lights;            // 자동차 조명의 상태

  public Car() {}            // 기본 생성자 (생략 가능)
}</code></pre></li>
</ul>
<h2 id="클래스-메서드-정의">클래스 메서드 정의</h2>
<h3 id="메서드">메서드</h3>
<ul>
<li><p>객체의 행위</p>
<pre><code>public class Car {
  String company;            // 자동차 회사
  String model;            // 자동차 모델
  String color;            // 자동차 색상
  double price;            // 자동차 가격
  double speed;            // 자동차 속도 (km/h)
  char gear;                // 기어의 상태 (P, R, N, D)
  boolean lights;            // 자동차 조명의 상태

  public Car() {}            // 기본 생성자 (생략 가능)

  double gasPedal(double kmh, char type) {
      changeGear(type);
      speed = kmh;
      return speed;
  }
  double brakePedal() {
      speed = 0;
      return speed;
  }
  char changeGear(char type) {
      gear = type;
      return gear;
  }
  boolean onOffLight() {
      lights = !lights;
      return lights;
  }
  void horn() {
      System.out.println(&quot;빵빵!&quot;);
  }
}</code></pre></li>
</ul>
<hr>
<h1 id="멤버">멤버</h1>
<p>[ 멤버 = 필드 + 메서드 ]</p>
<h2 id="인스턴스-멤버">인스턴스 멤버</h2>
<ul>
<li>인스턴스 필드 + 인스턴스 메서드</li>
<li>객체 생성 후에 사용할 수 있음</li>
</ul>
<h2 id="클래스-멤버">클래스 멤버</h2>
<ul>
<li>클래스 필드 + 클래스 메서드</li>
<li><code>static</code> 키워드 사용</li>
<li>객체 생성 없이 사용 가능함</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java - 자료구조 & JCF]]></title>
            <link>https://velog.io/@jilog_94/Java-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-JCF</link>
            <guid>https://velog.io/@jilog_94/Java-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-JCF</guid>
            <pubDate>Sun, 09 Apr 2023 01:05:37 GMT</pubDate>
            <description><![CDATA[<h1 id="자료구조">자료구조</h1>
<p>( Data Structure )
컴퓨터 프로그램에서 데이터를 처리하기 위해 만든 구조
데이터 값의 모임, 또 데이터 간의 관계, 그리고 데이터에 적용할 수 있는 함수나 명령의 집합
자료구조를 잘 선택하면 사용하는 메모리를 최소화 할 수 있으며 효율성을 확보할 수 있음</p>
<h2 id="형태에-따른-종류">형태에 따른 종류</h2>
<h3 id="■-선형">■ 선형</h3>
<p>선형(한 줄)으로 이루어진 자료구조</p>
<h4 id="--array">- Array</h4>
<ul>
<li>동일한 데이터 타입을 순서에 따라 관리하는 자료구조</li>
<li>정해진 크기가 있음 (정적배열)</li>
<li>인덱싱 되어 있어 인덱스 번호로 데이터에 접근할 수 있음</li>
</ul>
<h4 id="--linkedlist">- LinkedList</h4>
<ul>
<li>동일한 데이터 타입을 순서에 따라 관리하는 자료구조</li>
<li>정해진 크기가 없음 (동적배열)</li>
</ul>
<h4 id="--stack--filo-first-in-last-out">- Stack : FILO (First In Last Out)</h4>
<ul>
<li>맨 마지막 위치에서만 자료를 추가, 삭제, 꺼내올 수 있음</li>
</ul>
<h4 id="--queue--fifo-first-in-first-out">- Queue : FIFO (First In First Out)</h4>
<ul>
<li>순차적으로 입력된 자료를 순서대로 처리하는데 많이 사용되는 자료구조</li>
<li>맨 앞에서 자료를 꺼내거나 삭제하고, 맨 뒤에서 자료를 추가함</li>
</ul>
<h3 id="■-트리-tree">■ 트리 (Tree)</h3>
<p>부모 노드와 자식 노드간의 연결로 이루어진 자료구조 (계층적 구조)
TreeSet, TreeMap</p>
<h4 id="--이진-트리">- 이진 트리</h4>
<ul>
<li>자식 노드가 최대 2개인 트리</li>
</ul>
<h4 id="--완전-이진-트리">- 완전 이진 트리</h4>
<ul>
<li>마지막 레벨을 제외하고 모든 레벨이 완전히 채워져 있는 이진 트리</li>
</ul>
<h5 id="▲-힙-heap">▲ 힙 (Heap)</h5>
<ul>
<li>완전 이진 트리의 일종</li>
<li>여러 값 중 최대값과 최소값을 빠르게 찾아내도록 만들어진 자료구조</li>
<li>최대 힙 (max heap) : 부모 노드의 키 값이 자식 노드의 키 값보다 크거나 같은 완전 이진 트리</li>
<li>최소 힙 (min heap) : 부모 노드의 키 값이 자식 노드의 키 값보다 작거나 같은 완전 이진 트리</li>
</ul>
<h4 id="--전-이진-트리">- 전 이진 트리</h4>
<ul>
<li>모든 노드가 0개 또는 2개의 자식 노드를 갖는 이진 트리</li>
</ul>
<h4 id="--포화-이진-트리">- 포화 이진 트리</h4>
<ul>
<li>모든 레벨이 노드로 꽉 차 있는 이진 트리</li>
</ul>
<h4 id="--이진-탐색-트리">- 이진 탐색 트리</h4>
<ul>
<li>기존 이진 트리보다 탐색이 빠름</li>
</ul>
<h3 id="■-그래프-graph">■ 그래프 (Graph)</h3>
<p>여러 특성을 가지는 객체와 이 객체들의 연결 관계를 가지고 있는 자료구조
연결할 객체를 나타내는 정점(Vertext)과 객체를 연결하는 간선(Edge)의 집합</p>
<h4 id="--무방향-그래프">- 무방향 그래프</h4>
<ul>
<li>두 정점을 연결하는 간선에 방향이 없는 그래프</li>
</ul>
<h4 id="--방향-그래프">- 방향 그래프</h4>
<ul>
<li>간선에 방향이 있는 그래프</li>
</ul>
<h4 id="--완전-그래프">- 완전 그래프</h4>
<ul>
<li>한 정점에서 다른 모든 정점과 연결되서 최대 간선 수를 갖는 그래프</li>
</ul>
<h4 id="--부분-그래프">- 부분 그래프</h4>
<ul>
<li>기존의 그래프에서 일부 정점이나 간선을 제외하여 만든 그래프</li>
</ul>
<h4 id="--가중-그래프">- 가중 그래프</h4>
<ul>
<li>정점을 연결하는 간선에 가중치를 할당한 그래프</li>
</ul>
<h4 id="--유향-비순환-그래프">- 유향 비순환 그래프</h4>
<ul>
<li>방향 그래프에서 사이클이 없는 그래프</li>
</ul>
<h4 id="--연결-그래프">- 연결 그래프</h4>
<ul>
<li>떨어져 있는 정점이 없는 그래프</li>
</ul>
<h4 id="--단절-그래프">- 단절 그래프</h4>
<ul>
<li>연결되지 않은 정점이 있는 그래프</li>
</ul>
<h3 id="■-해시-hash">■ 해시 (Hash)</h3>
<p>ArrayList가 데이터 추가/삭제 시 많은 시간이 소요되는 점이나, LinkedList가 조회 시 효율이 떨어지는 점을 극복하기 위해서 제시된 방법
Key-Value(Hash Table) 형태의 자료구조로서 검색과 저장을 위한 자료구조
특정 데이터가 저장되는 인덱스를 그 데이터만의 고유한 위치로 정하여서 데이터 추가/삭제 시 데이터의 이동이 없도록 만들어진 구조</p>
<hr>
<h1 id="jcf">JCF</h1>
<p>(Java Collection Framework)
Java에서 데이터를 저장하는 자료구조들을 한 곳에 모아 편리하게 관리하고 사용하기 위해 제공하는 것
크게 List, Set, Map 으로 구분할 수 있음
이 모든건 import가 되어있어야 사용할 수 있음
<img src="https://velog.velcdn.com/images/jilog_94/post/cc154dfa-6a07-4ece-84f5-faeee76485d7/image.png" alt=""></p>
<h2 id="collection">Collection</h2>
<p>데이터의 그룹 집합체</p>
<ul>
<li>기능 : 크기 자동조정 / 추가 / 수정 / 삭제 / 반복 / 순회 / 필터 / 포함확인 등</li>
</ul>
<p>기본형 데이터가 아닌 참조형 데이터만 저장이 가능함
(기본형 데이터는 <a href="http://www.tcpschool.com/java/java_api_wrapper">Wrapper class</a>를 이용하여 Boxing 시켜주거나 autoBoxing으로 저장할 수 있음)
List와 Set, Queue 인터페이스의 많은 공통된 부분을 Collection 인터페이스에서 정의하고, 그것을 상속받음
(Collection 인터페이스를 상속받는 클래스들을 Collections라고 함)
Map은 Key-Value 라는 다른 구조를 가지기 때문에 독립적인 인터페이스가 구현되어있음</p>
<h3 id="■-list">■ List</h3>
<p>index 라는 식별자로 순서를 가짐
데이터 중복 허용</p>
<h4 id="--arraylist">- ArrayList</h4>
<ul>
<li>각 데이터에 대한 인덱스를 가지고 있어서 조회 기능에 성능이 뛰어남</li>
<li>Array와 달리 초기크기를 지정하지 않아도 되므로, 추가 삭제가 자유로움 (동적배열)</li>
<li>하지만 데이터의 추가, 삭제 시 많은 데이터가 밀리거나 당겨지기 때문에 많은 시간이 소요됨<pre><code>ArrayList&lt;Integer&gt; intList = new ArrayList&lt;Integer&gt;();        // 선언 + 생성
</code></pre></li>
</ul>
<p>// 추가
intList.add(1);
intList.add(2);
intList.add(3);</p>
<p>// 조회
System.out.println(intList.get(1));                // 2 (1번째 인덱스)
System.out.println(intList.toString());            // [1, 2, 3] (전체 배열 조회)</p>
<p>// 수정
intList.set(1, 10);                                // 1번째 인덱스 수정
System.out.println(intList.get(1));                // 10</p>
<p>// 삭제
intList.remove(0);                                // 0번째 인덱스 삭제
System.out.println(intList.get(0));                // 10</p>
<p>// 전체 삭제
intList.clear();
System.out.println(intList.toString());            // []</p>
<pre><code>
#### - LinkedList
- 데이터 삽입, 삭제가 빈번할 경우 데이터의 위치정보만 수정하면 됨
- 메모리에 남는 공간을 요청해서 실제 값을 여기저기 나누어서 담아놓음
- 실제 값이 있는 주소값으로 목록을 구성하고 저장하는 자료구조
- 기본적 기능은 ArrayList 와 동일
- 값을 여기저기 나눠놓았으므로 조회 속도는 느리고 값을 추가하거나 삭제할 때는 빠름
- 조회할 때 처음부터 순회 검색을 해야하기 때문에 데이터의 수가 많아질수록 효율이 떨어지는 구조</code></pre><p>LinkedList<Integer> linkedList = new LinkedList<Integer>();        // 선언 + 생성</p>
<p>// 추가
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);</p>
<p>// 조회
System.out.println(linkedList.get(1));            // 2 (1번째 인덱스)
System.out.println(linkedList.toString());        // [1, 2, 3] (전체 배열 조회)</p>
<p>// 중간에 값 추가
linkedList.add(2, 4);                            // 2번째 인덱스 자리에 값 4 추가
System.out.println(linkedList.toString());        // [1, 2, 4, 3]</p>
<p>// 수정
linkedList.set(1, 30);                            // 1번째 인덱스 수정
System.out.println(linkedList.get(1));            // 30 (1번째 인덱스)</p>
<p>// 삭제
linkedList.remove(1);                            // 1번째 인덱스 삭제
System.out.println(linkedList.toString());        // [1, 4, 3]</p>
<p>// 전체 삭제
linkedList.clear();
System.out.println(linkedList.toString());        // []</p>
<pre><code>
#### - Stack
- 수직으로 값을 쌓아놓고 넣었다가 뺌 (FILO)</code></pre><p>Stack<Integer> intStack = new Stack<Integer>();                // 선언 + 생성</p>
<p>// 추가
intStack.push(1);
intStack.push(2);
intStack.push(3);</p>
<p>// 조회
System.out.println(intStack.get(1));            // 2 (1번째 인덱스)
System.out.println(intStack.toString());        // [1, 2, 3] (전체 배열 조회)
System.out.println(intStack.peek());            // 3 (제일 마지막 추가 값 조회)
System.out.println(intStack.size());            // 3 (배열의 크기(사이즈) 조회)</p>
<p>// 다 지워질 때 까지 출력 (나중에 추가한 값부터 출력)
while (!intStack.isEmpty()) {
    System.out.println(intStack.pop());
}                                                // 3
                                                   2
                                                   1</p>
<pre><code>
#### - Vector
- ArrayList와 동일한 내부구조를 가짐
- 과거 대용량 처리를 위해 사용했으나 내부에서 자동으로 동기화처리가 일어나 비교적 성능이 좋지 않고 무거워 잘 쓰이지 않음

### ■ Set
순서가 없음
데이터 중복 불가
Set은 생성자가 없는 껍데기라서 바로 생성할 수 없고 HashSet, TreeSet 등으로 응용해서 사용 가능
#### - HashSet
- 순서를 예측할 수 없음

#### - TreeSet
- 정렬 방법을 지정할 수 있음</code></pre><p>Set<Integer> intSet = new HashSet&lt;&gt;();                        // 선언 + 생성</p>
<p>// 추가
intSet.add(1);
intSet.add(12);
intSet.add(5);
intSet.add(9);
intSet.add(1);
intSet.add(12);</p>
<p>// 조회
System.out.println(intSet.toString());            // [1, 5, 9, 12]</p>
<p>for (Integer value: intSet) {
    System.out.println(value);
}                                                // 1 (중복 없음)
                                                   5
                                                   9
                                                   12</p>
<p>// 포함 여부
System.out.println(intSet.contains(2));            // false
System.out.println(intSet.contains(5));            // true</p>
<pre><code>
### ■ Queue
- 먼저 들어간 자료가 먼저 나오는 구조 (FIFO)
- 생성자가 없는 인터페이스이므로 LinkedList를 활용해서 생성해야 함</code></pre><p>Queue<Integer> intQueue = new LinkedList&lt;&gt;();                // 선언 + 생성</p>
<p>// 추가
intQueue.add(1);
intQueue.add(2);
intQueue.add(3);</p>
<p>// 조회
System.out.println(((LinkedList<Integer>) intQueue).get(1));
                                                // 2 (1번째 인덱스)
System.out.println(intQueue.toString());        // [1, 2, 3] (전체 배열 조회)
System.out.println(intQueue.peek());            // 1 (제일 먼저 추가한 값 조회)
System.out.println(intQueue.size());            // 3 (배열의 크기(사이즈) 조회)</p>
<p>// 다 지워질 때까지 출력 (먼저 추가한 값부터 출력)
while (!intQueue.isEmpty()) {
    System.out.println(intQueue.poll());
}                                                // 1
                                                   2
                                                   3</p>
<pre><code>
### ■ Map
Key-Value 형태 자료구조
순서가 없음
Key는 중복 불가, Value는 중복 허용
Set처럼 HashMap, TreeMap 등으로 응용해서 사용 가능
#### - Hashtable
- null 불가

#### - HashMap
- null 허용

#### - TreeMap
- 정렬된 순서대로 Key-Value를 저장하여 검색이 빠름</code></pre><p>Map&lt;String, Integer&gt; intMap = new HashMap&lt;&gt;();                // 선언 + 생성</p>
<p>// 추가
intMap.put(&quot;일&quot;, 11);
intMap.put(&quot;이&quot;, 12);
intMap.put(&quot;삼&quot;, 13);
intMap.put(&quot;삼&quot;, 14);    // 중복 key
intMap.put(&quot;삼&quot;, 15);    // 중복 key (key가 중복되면 제일 나중에 입력된 value로 저장됨)</p>
<p>// 조회
System.out.println(intMap.toString());            // {이=12, 일=11, 삼=15}
System.out.println(intMap.get(&quot;삼&quot;));            // 15</p>
<p>for (String key: intMap.keySet()) {
    System.out.println(key);
}                                                // 이 (key 값 하나씩 전체 조회)
                                                   일
                                                   삼
for (Integer value: intMap.values()) {
    System.out.println(value);
}                                                // 12 (value 값 하나씩 전체 조회)
                                                   11
                                                   15
```</p>
]]></description>
        </item>
    </channel>
</rss>