<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>JWbase.velog</title>
        <link>https://velog.io/</link>
        <description>기억 저장소!!</description>
        <lastBuildDate>Tue, 23 Jan 2024 16:16:45 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>JWbase.velog</title>
            <url>https://velog.velcdn.com/images/dajw_program/profile/57b347c2-2ad1-4de5-a6c4-8e3509e41196/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. JWbase.velog. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dajw_program" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Docker에서 실행 중인 컨테이너 전체 삭제]]></title>
            <link>https://velog.io/@dajw_program/Docker%EC%97%90%EC%84%9C-%EC%8B%A4%ED%96%89-%EC%A4%91%EC%9D%B8-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%A0%84%EC%B2%B4-%EC%82%AD%EC%A0%9C</link>
            <guid>https://velog.io/@dajw_program/Docker%EC%97%90%EC%84%9C-%EC%8B%A4%ED%96%89-%EC%A4%91%EC%9D%B8-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%A0%84%EC%B2%B4-%EC%82%AD%EC%A0%9C</guid>
            <pubDate>Tue, 23 Jan 2024 16:16:45 GMT</pubDate>
            <description><![CDATA[<p>mac 환경에서 docker에서 실행 중인 컨테이너를 모두 삭제 하는 명령어</p>
<pre><code class="language-shell">docker rm -f $(docker ps -aq)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[맥에서 특정 포트 확인 및 종료]]></title>
            <link>https://velog.io/@dajw_program/%EB%A7%A5%EC%97%90%EC%84%9C-%ED%8A%B9%EC%A0%95-%ED%8F%AC%ED%8A%B8-%ED%99%95%EC%9D%B8-%EB%B0%8F-%EC%A2%85%EB%A3%8C</link>
            <guid>https://velog.io/@dajw_program/%EB%A7%A5%EC%97%90%EC%84%9C-%ED%8A%B9%EC%A0%95-%ED%8F%AC%ED%8A%B8-%ED%99%95%EC%9D%B8-%EB%B0%8F-%EC%A2%85%EB%A3%8C</guid>
            <pubDate>Tue, 23 Jan 2024 07:34:53 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-shell">sudo lsof -i :포트번호</code></pre>
<p>위 명령어를 입력하면 현재 포트번호의 PID가 나온다.</p>
<pre><code class="language-shell">sudo kill -9 PID</code></pre>
<p>해당 포트를 사용하고 있는 프로세스를 종료할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JPA - 엔티티 매핑]]></title>
            <link>https://velog.io/@dajw_program/JPA-%EC%97%94%ED%8B%B0%ED%8B%B0-%EB%A7%A4%ED%95%91</link>
            <guid>https://velog.io/@dajw_program/JPA-%EC%97%94%ED%8B%B0%ED%8B%B0-%EB%A7%A4%ED%95%91</guid>
            <pubDate>Mon, 08 Jan 2024 13:32:37 GMT</pubDate>
            <description><![CDATA[<h1 id="엔티티-매핑">엔티티 매핑</h1>
<ul>
<li>객체와 테이블 매핑</li>
<li>필드와 컬럼 매핑</li>
<li>기본 키 매핑</li>
<li>연관관계 매핑<h2 id="객체와-테이블-매핑">객체와 테이블 매핑</h2>
<h3 id="entity">@Entity</h3>
</li>
<li>@Entity가 붙은 클래스는 JPA가 관리하는 엔티티</li>
<li>주의<ul>
<li>기본 생성자가 필수(parameter가 없는 public or protected)</li>
<li>final class, enum, interface, inner class에는 사용할 수 없다.</li>
<li>저장할 필드에 final 키워드를 사용할 수 없다.</li>
</ul>
</li>
</ul>
<h2 id="데이터베이스-스키마-자동-생성">데이터베이스 스키마 자동 생성</h2>
<ul>
<li>DDL을 어플리케이션 실행 시점에 자동 생성(로딩 시점에 create table이 가능)</li>
<li>DB에 맞는 방언을 사용해서 적절한 DDL 생성</li>
<li>이렇게 <strong>생성된 DDL은 개발 장비에서만 사용!!</strong></li>
</ul>
<h2 id="필드와-컬럼-매핑">필드와 컬럼 매핑</h2>
<pre><code class="language-java">@Entity
@Table(name = &quot;MBR&quot;)
public class Member {

    @Id
    private Long id;

    @Column(name = &quot;name&quot;, updatable = false, nullable = false, length = 10, columnDefinition = &quot;varchar(100) default &#39;EMPTY&#39;&quot;)
    private String username;

    @Column()
    private BigDecimal age;

    @Enumerated(EnumType.STRING) //enum을 사용할 때 , ORDINAL은 지양 -&gt; ENUM의 순서가 바뀌면 알기 힘듦
    private RoleType roleType;

    @Temporal(TemporalType.TIMESTAMP) //java8 이후론 특별히 필요하지 않음
    private Date createDate;

    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;

    @Lob//varchar을 넘기는 큰 양의 문자를 사용할 때
    private String description;

    @Transient //db와 관계없이 메모리에서만 사용하고 싶을 때
    private int temp;

    protected Member() {
    }
}
</code></pre>
<ul>
<li><p>@Column()</p>
<ul>
<li>name : DB에서 실제 사용할 컬럼명을 설정</li>
<li>updatable : updatable = false이 되어 있으면 업데이트 쿼리가 날아가지 않음</li>
<li>nullable : NOT NULL 제약 조건</li>
<li>columnDefinition = varchar(100) default &#39;EMPTY&#39;, 컬렴을 직접 정의할 수 있음</li>
</ul>
</li>
<li><p>@Enumrated()</p>
<ul>
<li>Enum타입을 DB와 매핑할때 사용</li>
<li>EnumType: ORDINAL -&gt; ENUM의 순서대로(0, 1, 2...) 컬럼에 매핑 -&gt; 사용지양
  EnumType는 반드시 EnumType.STRING를 사용하는 것이 좋다.</li>
</ul>
<ul>
<li>@Temporal()<ul>
<li>날짜와 관련된 DB매핑</li>
<li>TemporalType : 표현방법에 맞게 DATE, TIME, TIMESTAMP 존재하는데 현재는 잘 사용하지 않는다.</li>
</ul>
</li>
</ul>
</li>
<li><p>@Lob</p>
<ul>
<li>clob, blob 타입에 사용</li>
</ul>
</li>
<li><p>@Transient</p>
<ul>
<li>DB매핑과 관계 없이 자바 내 메모리에서만 사용하고 싶을 때</li>
</ul>
</li>
</ul>
<h2 id="기본-키-매핑">기본 키 매핑</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[JPA - 플러시]]></title>
            <link>https://velog.io/@dajw_program/JPA-%ED%94%8C%EB%9F%AC%EC%8B%9C</link>
            <guid>https://velog.io/@dajw_program/JPA-%ED%94%8C%EB%9F%AC%EC%8B%9C</guid>
            <pubDate>Mon, 08 Jan 2024 09:27:00 GMT</pubDate>
            <description><![CDATA[<h1 id="플러시">플러시</h1>
<ul>
<li>영속성 컨텍스트의 변경내용을 데이터베이스에 반영</li>
</ul>
<h2 id="플러시-발생시-생기는-일">플러시 발생시 생기는 일</h2>
<ul>
<li>변경 감지</li>
<li>수정된 엔티티 쓰기 지연 SQL 저장소에 등록</li>
<li>쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송</li>
</ul>
<h2 id="영속성-컨텍스트를-플러시-하는-방법">영속성 컨텍스트를 플러시 하는 방법</h2>
<ul>
<li>em.flush() - 직접 호출<pre><code class="language-java">          Member member = new Member(200L, &quot;member200&quot;);
          em.persist(member);
          em.flush();
          //트랜잭션을 커밋하지 않아도 query가 실행된다.</code></pre>
</li>
<li>transaction commit - 플러시 자동 호출</li>
<li>JPQL 쿼리 실행 - 플러시 자동 호출</li>
</ul>
<h2 id="조심해야-할-부분">조심해야 할 부분</h2>
<ul>
<li>flush는 영속성 컨텍스트를 비우지는 않는다.</li>
<li>영속성 컨텍스트의 변경내용을 데이터베이스에 동기화 한다.</li>
<li>트랜잭션이라는 작업 단위가 있기 때문에 commit직전에만 db를 동기화하면 되기 때문에 flush가 가능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JPA - 영속성 컨텍스트]]></title>
            <link>https://velog.io/@dajw_program/JPA</link>
            <guid>https://velog.io/@dajw_program/JPA</guid>
            <pubDate>Mon, 08 Jan 2024 08:40:41 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>(해당 게시물은 <a href="https://www.inflearn.com/course/ORM-JPA-Basic/">JAVA ORM 표준 JPA 프로그래밍</a> 을 듣고 정리한 글 입니다.)</p>
</blockquote>
<h1 id="jpa에서-가장-중요한-두가지">JPA에서 가장 중요한 두가지!</h1>
<ul>
<li><strong>영속성 컨텍스트</strong></li>
<li>객체와 관계형 데이터 베이스 매핑하기(Object Relational Mapping)</li>
</ul>
<h1 id="영속성-컨텍스트">영속성 컨텍스트</h1>
<ul>
<li>JPA를 이애하는데 가장 중요한 용어로 <strong>&#39;엔티티를 영구 저장하는 환경&#39;</strong>이라는 뜻이다.</li>
<li>EntityManager.persist(entity); entity를 영속성 컨텍스트에 저장한다는 의미이다.</li>
<li>EntityManager와 PersistenceContext가 매핑됨.</li>
</ul>
<h2 id="엔티티의-생명주기">엔티티의 생명주기</h2>
<ul>
<li><p>비영속(new / transient)</p>
<ul>
<li><p>영속성 컨텍스트와 전혀 관계가 없는 <strong>새로운</strong> 상태</p>
<pre><code class="language-java">
Member member = new Member();
member.setId(&quot;1L&quot;);
member.setName(&quot;JWbase&quot;);

객체를 생성한 상태여서 영속성 컨텍스트에서 관리 되지 않는 비영속 상태라고 부른다.</code></pre>
</li>
</ul>
</li>
<li><p>영속 (managed)</p>
<ul>
<li><p>영속성 컨텍스트에 <strong>관리</strong>되는 상태</p>
<pre><code class="language-java">EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

// 객체를 저장한 상태 (영속)
em.persist(member);</code></pre>
</li>
<li><p>tracnsaction.commit()를 해야지만 DB에 query가 동작한다.</p>
</li>
</ul>
</li>
<li><p>준영속 (detached)    </p>
<ul>
<li>영속성 컨텍스트에 저장되었다가 <strong>분리</strong>된 상태<pre><code class="language-java">// 회원 엔티티를 영속성 컨텍스트에서 분리, 준 영속 상태
em.detach(member);</code></pre>
</li>
</ul>
</li>
<li><p>삭제 (removed)</p>
<ul>
<li><strong>삭제</strong>된 상태<pre><code class="language-java">em.remove(member);</code></pre>
<h2 id="영속성-컨텍스트의-이점">영속성 컨텍스트의 이점</h2>
</li>
</ul>
</li>
<li><p>1차 캐시</p>
</li>
<li><p>동일성(identity) 보장</p>
</li>
<li><p>트랜잭션을 지원하는 쓰기 지연(transactional write-behind)</p>
</li>
<li><p>변경 감지(Dirty Checking)</p>
</li>
<li><p>지연 로딩(Lazy Loading)</p>
</li>
</ul>
<h3 id="엔티티-조회-1차캐시">엔티티 조회, 1차캐시</h3>
<pre><code class="language-java">Member member = new Member();
member.setId(&quot;1L&quot;);
member.setName(&quot;JWbase&quot;);

//1차 캐시에 저장됨
em.persist(member);

//1차 캐시에서 조회
Member findMember = em.find(Member.class, &quot;1L&quot;);</code></pre>
<ul>
<li>만약 Member.findMember2 = em.find(Member.class, &quot;2L&quot;) 처럼 1차 캐시에 없는 객체를 영속성 컨텍스트에서 조회하면 DB에서 조회해서 조회해온 결과를 1차캐시에 저장하고 객체를 반환해준다.</li>
<li>보통 영속성 컨텍스트(엔티티 매니저)는 DB트랙잭션을 만들때 만들고 닫을 때 같이 날아가기 때문에 큰 장점은 없다.</li>
</ul>
<h3 id="동일성identity-보장">동일성(Identity) 보장</h3>
<pre><code class="language-java">            Member findMember1 = em.find(Member.class, 120L);
            Member findMember2 = em.find(Member.class, 120L);
            System.out.println(&quot;result = &quot; + (findMember1 == findMember2)); //true</code></pre>
<ul>
<li>1차 캐시로 반복 가능한 읽기(Repeatable read) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 어플리케이션 차원에서 제공한다.</li>
</ul>
<h3 id="트랜잭션을-지원하는-쓰기-지연">트랜잭션을 지원하는 쓰기 지연</h3>
<pre><code class="language-java">EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;hello&quot;);
        EntityManager em = emf.createEntityManager();
        EntityTransaction transaction = em.getTransaction();
        transaction.begin();

        em.persist(memberA);
        em.persist(memberB);
        //이 코드까지 실행되더라도 INSERT문을 날리지 않는다.

        //commit를 하는 순간에 INSERT문을 날린다.
        transacion.commit();</code></pre>
<h3 id="변경-감지">변경 감지</h3>
<pre><code class="language-java">Member member = em.find(Member.class, 160L);
member.setName(&quot;JWClassic&quot;); //em.persist(member)를 하지 않아도 update가 된다.</code></pre>
<ul>
<li>JPA는 commit시점에 flush()를 호출하고 엔티티와 스냅샷을 비교한다.</li>
<li>변경 된 점이 있다면 쓰기 지연 SQL 저장소에 UPDATE SQL을 생성하고 DB에 UPDATE SQL을 날린 후 커밋한다.</li>
</ul>
<h3 id="엔티티-삭제">엔티티 삭제</h3>
<pre><code class="language-java">Member memberA = em.find(Member.class, &quot;memberA&quot;);

em.remove(memberA); //엔티티 삭제</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[비교 연산자 <>]]></title>
            <link>https://velog.io/@dajw_program/%EB%B9%84%EA%B5%90-%EC%97%B0%EC%82%B0%EC%9E%90</link>
            <guid>https://velog.io/@dajw_program/%EB%B9%84%EA%B5%90-%EC%97%B0%EC%82%B0%EC%9E%90</guid>
            <pubDate>Sat, 06 Jan 2024 18:02:28 GMT</pubDate>
            <description><![CDATA[<h1 id="">&lt;&gt;</h1>
<p>MySQL에서 비교 연산자는 = 외에도 &lt;&gt; 연산자를 사용할 수 있다.
흔히 알고 있는 != 에 해당하는 연산자라고 생각하면 된다.
&lt;&gt; 연산자는 <strong>&#39;값이 서로 다른 경우&#39;</strong> 참이 되는 조건식으로 변경된다.</p>
<p>예를 들어</p>
<pre><code class="language-SQL">SELECT no, name
FROM sample21;</code></pre>
<p><img src="https://velog.velcdn.com/images/dajw_program/post/f1bcd3d3-b44e-41d1-925a-4f725660835c/image.png" alt=""></p>
<p>해당 데이터를 조회 했을 때 다음과 같은 값이 나온다고 하자.</p>
<pre><code class="language-SQL">SELECT no, name
FROM sample21
WHERE no = 2;</code></pre>
<p><img src="https://velog.velcdn.com/images/dajw_program/post/f7c76670-b7f6-4a87-8ad5-4ab16097d1de/image.png" alt=""></p>
<ul>
<li>no = 2 인 조건식을 걸어주면 no 컬럼에서 값이 2인 값만 나올 수 있다.</li>
</ul>
<p>&lt;&gt; 연산자의 경우는 </p>
<pre><code class="language-SQL">SELECT no, name
FROM sample21
WHERE no &lt;&gt; 2;</code></pre>
<p><img src="https://velog.velcdn.com/images/dajw_program/post/faa8eddb-9f68-4cb4-9bda-355d0efa6200/image.png" alt=""></p>
<ul>
<li>2가 아닌 경우를 출력하는 모습을 볼 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[스트림(Stream)을 알아보자!]]></title>
            <link>https://velog.io/@dajw_program/%EC%8A%A4%ED%8A%B8%EB%A6%BCStream%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dajw_program/%EC%8A%A4%ED%8A%B8%EB%A6%BCStream%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Thu, 30 Nov 2023 10:40:52 GMT</pubDate>
            <description><![CDATA[<h2 id="stream">Stream</h2>
<ul>
<li><p>Java8에서 추가 된 기능으로 연속 된 정보를 처리하는데 사용한다.
  자바에서 연속된 배열을 사용하는 경우는 보통 Array나 Collections에서 사용한다.</p>
<p>  다음과 같이 1, 3, 5라는 값이 정수 배열로 있을 때 asList() 메소드를 사용해서 List로 변환 한다.</p>
</li>
</ul>
<pre><code class="language-java">Integer[] values = { 1, 3, 5 };
List&lt;Integer&gt; list = new ArraysList&lt;&gt;(Arrays.asList(values));</code></pre>
<p>Arrays 클래스에 있는 stream()이라는 메소드를 사용해서 List로 변경하는 방법도 있다.</p>
<pre><code class="language-java">Integer[] values = { 1, 3, 5 };
List&lt;Integer&gt; list = Arrays.stream(values)
                            .collect(Collectors.toList());
</code></pre>
<h3 id="stream의-구조">Stream의 구조</h3>
<p>스트림은 다음과 같은 구조를 가진다.</p>
<pre><code class="language-java">    list.stream()
    .filter(x -&gt; x &gt; 10)
    .count();</code></pre>
<ul>
<li><p>스트림 생성( stream() ) : 컬렉션의 목록을 스트림 객체로 변환한다. 여기서 스트림 객체는 java.util.stream 패키지의 Stream 인터페이스를 뜻함.</p>
</li>
<li><p>중개 연산( filter(x -&gt; x &gt; 10 ) : 생성된 스트림 객체를 사용하여 중개 연산 부분에서 처리한다. <strong>하지만 이 부분에서는 아무런 결과를 리턴하지 못함</strong> 그래서 중개 연산(intermediate operation)이라고 부른다.</p>
</li>
<li><p>종단 연산( count() ) : 마지막으로 중개 연산에서 작업된 내용을 바탕으로 결과를 리턴</p>
</li>
</ul>
<p>중개 연산은 반드시 있어야 하는 것은 아니고 0개 이상의 중개 연산이 존재할 수 있다고 생각하는 것이 좋다.</p>
<p>stream()은 순차적으로 데이터를 처리한다. 즉, 10개의 데이터가 있다면 0 ~ 9번재 인덱스를 하나씩 처음부터 처리한다.</p>
<h3 id="stream에서-제공하는-연산의-종류">Stream에서 제공하는 연산의 종류</h3>
<p>스트림에서는 다양한 종류의 연산을 제공하지만 지금은 일반적으로 많이 사용되는 연산자(foreach(), map(), filter())를 알아 보자</p>
<h4 id="foreach"><em><strong>foreach()</strong></em></h4>
<ul>
<li>for 루프를 수행하는 것처럼 각각의 항목을 꺼냄</li>
</ul>
<pre><code class="language-java">@Getter
@Setter
public class StudentDTO {
    private String name;
    private int age;
    private int scoreMath;
    private int scoreEnglish;

    public StudentDTO(String name, int age, int scoreMath, int scoreEnglish) {
        this.name = name;
        this.age = age;
        this.scoreMath = scoreMath;
        this.scoreEnglish = scoreEnglish;
    }
}</code></pre>
<pre><code class="language-java">import java.util.ArrayList;
import java.util.List;

public class StudentForEachSample {
    public static void main(String[] args) {
        StudentForEachSample sample = new StudentForEachSample();

        List&lt;StudentDTO&gt; studentList = new ArrayList&lt;&gt;();
        studentList.add(new StudentDTO(&quot;베이스&quot;, 40, 100, 100));
        studentList.add(new StudentDTO(&quot;스트림&quot;, 30, 85, 55));
        studentList.add(new StudentDTO(&quot;포이치&quot;, 20, 95, 75));

        sample.printStudentName(studentList);
    }

    private void printStudentName(List&lt;StudentDTO&gt; students) {
        students.stream()
                .forEach(student -&gt; System.out.println(student.getName()));
    }
}</code></pre>
<p>printStudentName() 메소드를 보면 학생들의 이름을 출력하는 기능을 하고 있다.</p>
<p>students.stream()까지는 스트림을 생성하는 부분이여서 넘어가고 forEach()를 보자.
람다식을 이용해서 매개변수로 넘어온 students List에서 하나의 studentDTO 객체를 의미한다.</p>
<pre><code class="language-java">forEach(student -&gt; System.out.println(student.getName());

// 해당 코드는 위 코드와 동일한 기능을 한다.
for(StudentDTO student : students) {
    System.out.println(student.getName());
}
</code></pre>
<h4 id="map"><em><strong>map()</strong></em></h4>
<ul>
<li>데이터를 특정 데이터로 변환</li>
</ul>
<p>위에서 확인한 스트림의 구조를 다시 살펴보면</p>
<pre><code class="language-java">    list.stream()
    .filter(x -&gt; x &gt; 10)
    .count();</code></pre>
<p>앞 서 설명했던 forEach() 메소드 같은 경우에는 종단 연산에 속하고 지금 살펴 볼 map() 메소드의 경우는 중개 연산에 속한다.</p>
<pre><code class="language-java">List&lt;Integer&gt; intList = Arrays.asList(1,2,3,4,5,6);</code></pre>
<ul>
<li>해당 리스트를 모두 * 3해서 출력하는 예제이다.</li>
</ul>
<pre><code class="language-java">private void mulitplayWithFor(List&lt;Integer&gt; integerList) {
        for (Integer value : integerList) {
            int tempValue = value * 3;
            System.out.println(tempValue);
        }
    }</code></pre>
<pre><code class="language-java">private void mulitplayWithFor(List&lt;Integer&gt; integerList) {
        for (Integer value : integerList) {
            System.out.println(value * 3);
        }
    }</code></pre>
<p> 스트림을 사용하지 않으면 보통 이런식으로 작성하는 경우가 대부분이라고 생각한다.
 스트림을 사용하면 이런식으로 작성할 수 있다.</p>
<pre><code class="language-java">     private void mulitplayWithFor(List&lt;Integer&gt; integerList) {
        integerList.stream()
                .forEach(value -&gt; System.out.println(value * 3));
    }</code></pre>
<p> 하지만 3배로 변환된 값의 합을 구한다고 하면 복잡해진다. 이럴때 map()을 이용해서 편하게 사용할 수 있다.</p>
<pre><code class="language-java">        integerList.stream()
                .map(x -&gt; x * 3)
                .forEach(System.out::println);</code></pre>
<p>map(x -&gt; x * 3)을 거치고 나면 {1, 2, 3, 4, 5, 6}의 값이 {3, 6, 9, 12, 15, 18}로 변경된다.
또한, map()은 숫자 뿐만 아니라 객체도 변경이 가능하다. 위의 예제 인 StudentDTO 리스트에서 이름만 추출해서 List로 뽑아내보도록 하자.</p>
<pre><code class="language-java">List&lt;StudentDTO&gt; studentList = new ArrayList&lt;&gt;();
        studentList.add(new StudentDTO(&quot;베이스&quot;, 40, 100, 100));
        studentList.add(new StudentDTO(&quot;스트림&quot;, 30, 85, 55));
        studentList.add(new StudentDTO(&quot;포이치&quot;, 20, 95, 75));

        List&lt;String&gt; studentNames = studentList.stream()
                .map(studnet -&gt; studnet.getName())
                .collect(Collectors.toList());
</code></pre>
<p>이런 식으로 StudentDTO 객체에 있는 name값만 추출해서 리스트로 반환할 수 있다.</p>
<h4 id="filter"><em><strong>filter()</strong></em></h4>
<ul>
<li>데이터를 조건으로 거를때 사용
위의 예제에서 수학 점수가 90점 이상 인 사람의 이름만 출력하도록 해보자<pre><code class="language-java">  private void filterWithMathScoreForLoop(List&lt;StudentDTO&gt; studentList, int scoreCutLine) {
      for (StudentDTO studnet : studentList) {
          if (studnet.getScoreMath() &gt; scoreCutLine) {
              System.out.println(studnet.getName());
          }
      }
  }</code></pre>
해당 코드를 스트림을 사용해 작성하면<pre><code class="language-java">  private void filterWithMathScoreForLoop(List&lt;StudentDTO&gt; studentList, int scoreCutLine) {
      studentList.stream()
              .filter(student -&gt; student.getScoreMath() &gt; scoreCutLine)
              .forEach(student -&gt; System.out.println(student.getName()));
  }</code></pre>
이렇게 나타낼 수 있다. 즉, filter는 조건문 처럼 스트림 내에서 필요한 데이터를 걸러서 처리할 때 사용한다.</li>
</ul>
<h3 id="stream-정리">Stream 정리</h3>
<ul>
<li>스트림은 Collction과 같이 목록을 처리할 때 유용하게 사용<ul>
<li>스트림 생성 - 중간 연산 - 종단 연산으로 구분</li>
<li>중간 연산은 데이터를 가공할 때 사용되고 연산 결과로 Stream 타입을 리턴하기 때문에 여러개의 중간 연산을 연결할 수 있음</li>
<li>종단 연산은 스트림 처리를 마무리 하기 위해 사용되며, 숫자나 List같은 데이터를 리턴</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java Collection(List, Set, Map)]]></title>
            <link>https://velog.io/@dajw_program/JAVA-CollectionList-Set-Map</link>
            <guid>https://velog.io/@dajw_program/JAVA-CollectionList-Set-Map</guid>
            <pubDate>Mon, 27 Feb 2023 07:37:37 GMT</pubDate>
            <description><![CDATA[<h1 id="collection-framework">Collection Framework</h1>
<h2 id="종류">종류</h2>
<p><img src="https://velog.velcdn.com/images/dajw_program/post/a4b72b21-e1d3-4f79-a96a-53116202ae7b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dajw_program/post/c34761eb-3034-4995-9f03-af41993beecf/image.png" alt=""></p>
<h3 id="list-컬렉션">List 컬렉션</h3>
<ul>
<li><p>객체를 인덱스로 관리하기 때문에 인덱스로 검색, 삭제 할 수 있는 기능 제공</p>
</li>
<li><p>종류 : ArrayList, Vector, LinkedList
<img src="https://velog.velcdn.com/images/dajw_program/post/6aa3bd09-fa77-4354-9fb6-e4418a7f53d8/image.png" alt=""></p>
</li>
<li><p>ArrayList</p>
<ul>
<li>가장많이 사용하는 List Collection</li>
<li>길이의 제한 없이 객체를 추가 할 수 있음</li>
<li>객체의 번지를 저장 -&gt; 동일한 객체 중복저장 시 동일한 번지 저장</li>
<li>null 저장가능<pre><code class="language-java">  List&lt;E&gt; list = new ArrayList&lt;E&gt;(); // E에 지정된 타입의 객체만 저장
    List&lt;E&gt; list = new ArrayList&lt;&gt;(); // E에 지정된 타입의 객체만 저장
    List list = new ArrayList(); // 모든 타입의 객체 저장</code></pre>
</li>
<li>객체 추가시 인덱스 0번부터 차례대로 저장</li>
<li>특정 인덱스의 객체 제거시 앞으로 1씩 당겨짐</li>
<li>객체 삭제 및 삽입이 자주 일어나면 비효율</li>
</ul>
</li>
<li><p>Vector</p>
<ul>
<li>ArrayList와 동일한 구조</li>
<li>동기화(Synchronized)된 메소드로 구성 되어 있어 멀티 스레드가 Vector() 메소드 실행X</li>
<li>안전하게 객체 추가 또는 삭제<pre><code class="language-java">    List&lt;E&gt; list = new Vector&lt;E&gt;(); // E에 지정된 타입의 객체만 저장
    List&lt;E&gt; list = new Vector&lt;&gt;(); // E에 지정된 타입의 객체만 저장
   List list = new Vector(); // 모든 타입의 객체 저장</code></pre>
</li>
</ul>
</li>
<li><p>LinkedList</p>
<ul>
<li><p>인접 객체를 체인처럼 연결해서 관리
<img src="https://velog.velcdn.com/images/dajw_program/post/e36f2cc6-0ab0-4d5c-bd99-275363b93e61/image.png" alt=""></p>
</li>
<li><p>삽입, 삭제시 앞뒤 링크만 변경하면 되므로 빈번한 삽입이 일어나는 곳에 사용
<img src="https://velog.velcdn.com/images/dajw_program/post/f57f762c-839d-4cb9-b9ef-b5e78dce7f17/image.png" alt=""></p>
<pre><code class="language-java">     List&lt;E&gt; list = new LinkedList&lt;E&gt;(); // E에 지정된 타입의 객체만 저장
       List&lt;E&gt; list = new LinkedList&lt;&gt;(); // E에 지정된 타입의 객체만 저장
       List list = new LinkedList(); // 모든 타입의 객체 저장</code></pre>
</li>
</ul>
</li>
</ul>
<hr>

<h3 id="set-컬렉션">Set 컬렉션</h3>
<ul>
<li><p>저장 순서가 유지 되지 않음</p>
</li>
<li><p>중복 저장 X</p>
</li>
<li><p>하나의 null만 저장 가능</p>
</li>
<li><p>수학의 집합에 비유</p>
</li>
<li><p>종류 : HashSet, TreeSet
<img src="https://velog.velcdn.com/images/dajw_program/post/b58ee11d-c4c9-424a-a387-290253f35b63/image.png" alt=""></p>
</li>
<li><p>HashSet</p>
<ul>
<li>가장 많이 사용 되는 Set 컬렉션<pre><code class="language-java">  Set&lt;E&gt; set = new HashSet&lt;E&gt;(); // E에 지정된 타입의 객체만 저장
    Set&lt;E&gt; set = new HashSet&lt;&gt;(); // E에 지정된 타입의 객체만 저장
    Set set = new HashSet(); // 모든 타입의 객체를 저장</code></pre>
</li>
<li>HashCode() 리턴값이 같고, equals() true 리턴 -&gt; 동일한 객체이므로 중복저장X</li>
</ul>
</li>
</ul>
<h3 id="map-컬렉션">Map 컬렉션</h3>
<ul>
<li><p>key와 value로 구성된 Entry객체 저장</p>
</li>
<li><p>key는 중복 X, value는 중복 O</p>
</li>
<li><p>종류 : HaspMap, Hashtable, TreeMap, Properties, LinkedHashMap
<img src="https://velog.velcdn.com/images/dajw_program/post/affe8a27-7a5c-4f3b-a685-23281190f726/image.png" alt=""></p>
</li>
<li><p>HashMap</p>
<ul>
<li>키 객체가 HashCode() 메소드의 리턴값이 같고 equals() 메소드가 true면 동일 키로 본다.</li>
<li>HashMap 생성 하는방법<pre><code class="language-java">Map&lt;K, V&gt; map = new HashMap&lt;K, V&gt;();</code></pre>
</li>
</ul>
</li>
<li><p>Hashtable</p>
<ul>
<li>HaspMap과 동일한 내부</li>
<li>동기화된 메소드로 구성되어 멀티 스레드가 동시에 Hashtable 메소드 실행 X</li>
<li>멀티 스레드 환경에서도 안전하게 추가, 삭제<pre><code class="language-java">Map&lt;String, Integer&gt; map = new Hashtable&lt;&gt;();</code></pre>
</li>
</ul>
</li>
<li><p>Properties</p>
<ul>
<li>Hashtable의 자식 클래스로 Hashtable의 특징을 그대로 가지고 있음</li>
<li>key, value를 String으로 제한한 컬렉션</li>
<li>주로 .properties인 프로퍼티 파일을 읽을 때 사용</li>
<li>프로퍼티 파일은 key , value가 = 기호로 연결되어 있는 텍스트 파일</li>
<li>ISO 8859-1 문자셋, 한글은 \u + 유니코드<pre><code class="language-java">// database.properties 파일
  dirver=oracle.jdbc.OracleDriver
    url=jdbc:oracle:thin:@localhost:1521:orcl
    username=scott
    password=tiger
  admin=\uD64D\uAE38\u3D9
</code></pre>
</li>
</ul>
<p>// Properties 파일 읽는법</p>
<pre><code>Properties properties = new Properties();
  properties.load(Xxx.class.getResourceAsStream(&quot;database.properties&quot;));</code></pre><pre><code></code></pre></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[깃 허브 커밋 메시지 컨벤션 예시]]></title>
            <link>https://velog.io/@dajw_program/%EA%B9%83%ED%97%88%EB%B8%8C-%EC%BB%A4%EB%B0%8B%EB%A9%94%EC%8B%9C%EC%A7%80-%EC%98%88%EC%8B%9C</link>
            <guid>https://velog.io/@dajw_program/%EA%B9%83%ED%97%88%EB%B8%8C-%EC%BB%A4%EB%B0%8B%EB%A9%94%EC%8B%9C%EC%A7%80-%EC%98%88%EC%8B%9C</guid>
            <pubDate>Sun, 26 Feb 2023 01:45:46 GMT</pubDate>
            <description><![CDATA[<h3 id="영어">영어</h3>
<ul>
<li>fix: for bug fixes</li>
<li>docs: for documentation updates</li>
<li>style: for code style changes (e.g. whitespace, formatting)</li>
<li>refactor: for code refactoring (i.e. improving the code without changing its functionality)</li>
<li>test: for adding or updating tests</li>
<li>chore: for changes to build processes, tooling, or other non-code changes</li>
</ul>
<h3 id="한글">한글</h3>
<ul>
<li>수정: 버그 수정</li>
<li>문서: 문서 업데이트</li>
<li>스타일: 코드 스타일 변경 (예: 공백, 서식)</li>
<li>리팩터링: 코드 리팩터링 (즉, 기능을 변경하지 않고 코드를 개선)</li>
<li>테스트: 테스트 추가 또는 업데이트</li>
<li>기타: 빌드 프로세스, 도구 또는 기타 비코드 변경 사항</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Collections.shuffle]]></title>
            <link>https://velog.io/@dajw_program/Collections.shuffle</link>
            <guid>https://velog.io/@dajw_program/Collections.shuffle</guid>
            <pubDate>Fri, 24 Feb 2023 05:36:25 GMT</pubDate>
            <description><![CDATA[<h3 id="shuffle-메소드">shuffle 메소드</h3>
<ul>
<li>Colletions에 있는 메소드 중 shuffle() 메소드는 배열이나 리스트를 랜덤으로 출력할 때 사용</li>
</ul>
<pre><code class="language-java">public class ShuffleEx {
    public static void main(String[] args) {

        ArrayList&lt;String&gt; fruitList = new ArrayList&lt;&gt;();
        fruitList.add(&quot;apple&quot;);
        fruitList.add(&quot;banana&quot;);
        fruitList.add(&quot;grape&quot;);
        fruitList.add(&quot;melon&quot;);
        fruitList.add(&quot;orange&quot;);

        System.out.println(&quot;fruitList = &quot; + fruitList);

        Collections.shuffle(fruitList);
        System.out.println(&quot;shuffleFruitList = &quot; + fruitList);
    }
}</code></pre>
<pre><code>fruitlist = [apple, banana, grape, melon, orange]
shuffleFruitList = [melon, banana, orange, grape, apple]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[SpringMVC 구조]]></title>
            <link>https://velog.io/@dajw_program/SpringMVC-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@dajw_program/SpringMVC-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Fri, 24 Feb 2023 04:44:41 GMT</pubDate>
            <description><![CDATA[<h1 id="스프링mvc-구조">스프링MVC 구조</h1>
<p><img src="https://velog.velcdn.com/images/dajw_program/post/b00df54c-7346-4a4f-951b-4bab9db5a72e/image.png" alt=""></p>
<ol>
<li>핸들러 조회 : 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회한다.</li>
<li>핸들러  어댑터 조회 : 핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다.</li>
<li>핸들러 어댑터 실행 : 핸들러 어댑터를 실행한다.</li>
<li>핸들러 실행: 핸들러 어댑터가 실제 핸들러를 실행</li>
<li>ModelAndView반환 : 핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해서 반환</li>
<li>viewResolver호출: 뷰 리졸버를 찾고 실행한다.</li>
</ol>
<ul>
<li>JSP의 경우 : InternalResourceViewResolver가 자동 등록되고, 사용된다.</li>
</ul>
<ol start="7">
<li>View 반환 : 뷰 리졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환</li>
</ol>
<h3 id="dispatcherservelt-구조-살펴보기">DispatcherServelt 구조 살펴보기</h3>
<ul>
<li><p>스프링 MVC의 프론트컨트롤러 = DispatcherServlet</p>
</li>
<li><p>DispathcerServlet이 스프링 MVC의 핵심</p>
</li>
<li><p>DispathcerServlet도 부모 클래스에서 HttpServlet을 상속받아서 사용하고, 서블릿으로 동작</p>
<ul>
<li>DispathcerServlet -&gt; FrameWorkServlet -&gt; HttpSerlvetBean -&gt; HttpServlet</li>
</ul>
</li>
<li><p>스프링 부트는 DispathcerServlet을 서블릿으로 자동으로 등록하면서 모든경로(urlPatterns=&quot;/&quot;)에 대해서 매핑</p>
<ul>
<li>참고 : 더 자세한 경로가 우선순위가 높아서 기존에 등록한 서블릿도 함께 동작</li>
</ul>
</li>
</ul>
<h3 id="요청흐름">요청흐름</h3>
<ul>
<li>서블릿이 호출되면 HttpServlet이 제공하는 service()가 호출</li>
<li>스프링 MVC는 DispathcerServlet의 부모님 FrameWork에서 service()를 오버라이드</li>
<li>FrameworkServlet.service()를 시작으로 여러 메서드가 호출되면서 DispathcerServlet.doDispatch()가 호출</li>
</ul>
<h4 id="dispathcerservletdodispatch">DispathcerServlet.doDispatch()</h4>
<pre><code class="language-java">protected void doDispatch(HttpServletRequest request, HttpServletResponse
response) throws Exception {

    HttpServletRequest processedRequest = request;
    HandlerExcutionChain mappedHandler = null;
    ModelAndView mv = null;

    // 1. 핸들러 조회
    mappedHandler = getHandler(processedRequest);
    if(mappedHandler == null) {
        noHandlerFound(processedRequest, response);
        return;
    }

    // 2. 핸들러 어댑터 조회 - 핸들러를 처리할 수 있는 어댑터
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

    // 3. 핸들러 어댑터 실행 -&gt; 4. 핸들러 어댑터를 통해 핸들러 실행 -&gt; 5. ModelAndView 반환
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}

private void processDispathchResult(HttpServletRequest request,
HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, 
Exception exception) throws Exception {
    // 뷰 렌더링 호출
    render(mv, request, response);
}

protected void render(ModelAndView mv, HttpServletRequest request,
HttpServletResponse response) throws Exception {
    // 6. 뷰 리졸버를 통해서 뷰찾기,
    // 7. View 반환
    view = resolveViewName(viewName, mv.getModelInternal(), locale, request);

    // 8. 뷰 렌더링
    view.render(mv.getModelInternal(), request, response);
}</code></pre>
<ul>
<li>스프링 MVC의 큰 강점은 DispathcerServlet 코드의 변경없이, 원하는 기능을 변경하거나 확장 할수 있다.</li>
<li>인터페이스만 구현해서 DispathcerServlet에 등록하면 컨트롤러를 만들 수 있음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Logging 알아보기]]></title>
            <link>https://velog.io/@dajw_program/Logging-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@dajw_program/Logging-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Fri, 24 Feb 2023 01:57:57 GMT</pubDate>
            <description><![CDATA[<h1 id="logging을-사용">logging을 사용</h1>
<ul>
<li>운영 시스템에서는 System.out.println()같은 시스템 콘솔을 사용하지 않고 SLF4J 로깅 라이브러리를 사용한다.</li>
<li>로그 라이브러리는 Logback, Log4J, Log4J2등 수많은 라이브러리가 있는데 통합해서 인터페이스로 제공하는 것이 SLF4J 인터페이스</li>
<li>실무에서는 보통 스프링부트가 기본으로 제공하는 Logback을 대부분 사용</li>
</ul>
<h3 id="로그-선언">로그 선언</h3>
<pre><code class="language-java">private Logger log = LoggerFactory.getLogger(getClass());
private static final Logger log = LoggerFactory.getLogger(Xxx.class));
@Slf4j: 롬복 사용</code></pre>
<h3 id="로그호출">로그호출</h3>
<pre><code class="language-java">log.info(&quot;hello&quot;);
System.out.println(&quot;hello)</code></pre>
<pre><code class="language-java">@RestController
public class LogTestController {
    private final Logger log = LoggerFactory.getLogger(getClass());
        @RequestMapping(&quot;/log-test&quot;)
        public String logTest() {
            String name = &quot;Spring&quot;;
            log.trace(&quot;trace log={}&quot;, name);
            log.debug(&quot;debug log={}&quot;, name);
            log.info(&quot; info log={}&quot;, name);
            log.warn(&quot; warn log={}&quot;, name);
            log.error(&quot;error log={}&quot;, name);
            //로그를 사용하지 않아도 a+b 계산 로직이 먼저 실행됨, 이런 방식으로 사용하면 X
            log.debug(&quot;String concat log=&quot; + name);
            return &quot;ok&quot;;
}</code></pre>
<ul>
<li><p>@RestController</p>
<ul>
<li>@Controller는 반환 값이 String이면 viewName으로 인식, 그래서 view를 찾고 view가 랜더링</li>
<li>@RestController는 반환 값으로 view를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력
따라서, return 에 ok를 바로 메시지로 받을 수 있다.</li>
</ul>
</li>
<li><p>테스트</p>
<ul>
<li>로그가 출력되는 포멧을 확인<pre><code class="language-java">2023-02-24 09:41:22.364  INFO 13428 --- [nio-8080-exec-2] hello.springmvc.basic.LogTestController  : info log=Spring </code></pre>
</li>
<li>시간(2023-02-24 09:41:22.364), 로그레벨(INFO),</li>
<li>프로세스ID(13428), </li>
<li>쓰레드명([nio-8080-exec-2]), </li>
<li>클래스명(hello.springmvc.basic.LogTestController), </li>
<li>로그메시지(info log=Spring)</li>
</ul>
</li>
<li><p>로그 레벨 설정</p>
<ul>
<li>src/main/resources/application.properties 파일에서 설정<pre><code class="language-java">#전체 로그 레벨 설정(기본은 info)
logging.level.root=info
</code></pre>
</li>
</ul>
<p>#hello.springmvc 패키지와 그 하위 로그 레벨 설정
logging.level.hello.springmvc=debug
````</p>
</li>
<li><p>올바른 로그 사용법</p>
<pre><code class="language-java">log.debug(&quot;data =&quot; + data)
          /*로그 출력 레벨을 info로 설정해도 해당 코드에 있는 &quot;data=&quot; + data가
          실제 실행이 되어버려 결과적으로 문자더하기 연산이 발생) */
 log.debug(&quot;data = {}&quot;, data)
          /* 로그 출력레벨을 info로 설정하면 아무일도 발생하지 않아서 의미없는 연산이 발생하지 않음</code></pre>
</li>
<li><p>로그 사용시 장점</p>
<ul>
<li>쓰레드정보, 클래스 이름 같은 부가 정보를 함께 볼 수 있고, 출력 모양을 결정</li>
<li>로그 레벨에 따라 개발 서버에는 모든 로그를 출력하고, 운영서버에서는 출력하지 않는 등 로그를 상황에 맞게 조절할 수 있다.</li>
<li>시스템 아웃 콘솔에만 출력하는 것이 아니라, 파일, 네트워크 등, 로그를 별도의 위치에 남길 수 있음
특히, 파일로 남길 때는 특정용량, 일별에 따라 로그를 분할하는 것도 가능</li>
<li>성능도 System.out보다 좋음(내부 버퍼링, 멀티 쓰레드)</li>
<li><blockquote>
<p>실무에서는 꼭 로그를 사용하자!</p>
</blockquote>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>