<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>brave_chicken.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 06 Aug 2024 04:48:53 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>brave_chicken.log</title>
            <url>https://velog.velcdn.com/images/brave_chicken/profile/12408c8e-869b-48de-8e1e-00577b4c43c3/image.jfif</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. brave_chicken.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/brave_chicken" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[알고리즘 공부 : 삼항 연산자, 2차원 배열]]></title>
            <link>https://velog.io/@brave_chicken/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B3%B5%EB%B6%80-240806</link>
            <guid>https://velog.io/@brave_chicken/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B3%B5%EB%B6%80-240806</guid>
            <pubDate>Tue, 06 Aug 2024 04:48:53 GMT</pubDate>
            <description><![CDATA[<h3 id="삼항-연산자">삼항 연산자</h3>
<p>조건부 연산자로, 자바에서 ?와 :를 사용하여 작성
간단한 조건문을 한 줄로 표현할 수 있어 코드가 더 간결해짐</p>
<pre><code class="language-java">result = (condition) ? valueIfTrue : valueIfFalse;</code></pre>
<ul>
<li>condition : 평가될 조건식. 조건식의 결과는 true 또는 false</li>
<li>valueIfTrue: 조건이 true일 때 반환될 값</li>
<li>valueIfFalse: 조건이 false일 때 반환될 값</li>
</ul>
<p>예제</p>
<pre><code class="language-java">int a = 5;
int b = 10;
int max = (a &gt; b) ? a : b;</code></pre>
<p>max = 10</p>
<h3 id="2차원-배열">2차원 배열</h3>
<p>2차원 배열은 배열의 배열로 구성되며, 행과 열의 형태로 데이터를 저장</p>
<ul>
<li><p>2차원 배열 선언</p>
<pre><code class="language-java">int[][] arr;</code></pre>
</li>
<li><p>2차원 배열 초기화</p>
<ol>
<li>정적 초기화 (크기 지정 후 값 설정)<pre><code class="language-java">int[][] arr = new int[3][4]; // 3행 4열의 2차원 배열 선언</code></pre>
</li>
<li>동적 초기화 (값을 직접 지정)<pre><code class="language-java">int[][] arr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};</code></pre>
</li>
</ol>
</li>
</ul>
<p>ex. arr[1][2]는 두 번째 행의 세 번째 요소</p>
<h3 id="배열-랜덤으로-가져오기">배열 랜덤으로 가져오기</h3>
<pre><code class="language-java">import java.util.Random;</code></pre>
<pre><code class="language-java">Random ran = new Random();
dice[ran.nextInt(6)]</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[빅데이터분석기사 필기 참고 사이트]]></title>
            <link>https://velog.io/@brave_chicken/%EB%B9%85%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D%EA%B8%B0%EC%82%AC-%ED%95%84%EA%B8%B0-%EC%B0%B8%EA%B3%A0-%EC%82%AC%EC%9D%B4%ED%8A%B8</link>
            <guid>https://velog.io/@brave_chicken/%EB%B9%85%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D%EA%B8%B0%EC%82%AC-%ED%95%84%EA%B8%B0-%EC%B0%B8%EA%B3%A0-%EC%82%AC%EC%9D%B4%ED%8A%B8</guid>
            <pubDate>Tue, 06 Aug 2024 01:00:42 GMT</pubDate>
            <description><![CDATA[<p><a href="https://cbt.youngjin.com/exam/index.php?no=69">영진닷컴 빅분기 기출</a>
<a href="https://ohaengsa.tistory.com/category/%EC%9E%90%EA%B2%A9%EC%A6%9D/%EB%B9%85%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D%EA%B8%B0%EC%82%AC?page=3">빅분기 기출 정리</a>
<a href="https://www.youtube.com/watch?v=Gynhu746Hqk&amp;list=PL6i7rGeEmTvqIv1WAV3HnyaPmOFT04ou2">유튜브 빅분기 기출 3-6회차 해설 </a>
<a href="https://www.youtube.com/watch?v=2pzPpiNTaCk&amp;list=PLWtr7MRpQi5Dt41ZE0mT_wFIWUsTT1E7O">유튜브 빅분기 요약강의</a>
<a href="https://gagadi.tistory.com/35">문과 비전공자 합격수기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[팀프로젝트 최종발표 후기]]></title>
            <link>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B5%9C%EC%A2%85%EB%B0%9C%ED%91%9C</link>
            <guid>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B5%9C%EC%A2%85%EB%B0%9C%ED%91%9C</guid>
            <pubDate>Mon, 15 Jul 2024 14:11:15 GMT</pubDate>
            <description><![CDATA[<h3 id="김서연-강사님-피드백">김서연 강사님 피드백</h3>
<ul>
<li>길찾기, 크롤링 스케줄러 등 지나가는 말로 이야기한 기능도 다 구현을 했다. </li>
<li>이메일을 실제 상업메일처럼 잘 구성해서 보낸 것도 인상적이었다.</li>
<li>관심설정 추천이메일은 서비스화한다면 대용량으로 처리해야하는 이슈가 발생할것. 여러 기술들을 공부해서 이부분 완성하면 좋을 것 같다.</li>
</ul>
<h3 id="외부-심사위원님-피드백">외부 심사위원님 피드백</h3>
<ul>
<li>팝업스토어 정보를 모아서 보여준것 외에도 좋아요, 후기, 대기, 예약 등 사용자 활동기능이 있는게 좋았다.</li>
<li>기능의 갯수나 유즈케이스를 잘 정리해서 구현했다.</li>
<li>초반 DB설계가 잘 되어서 후에 좋은 영향을 준 것 같다.</li>
<li>이벤트 별로 달라질수있는 데이터나 정책이 있을 수 있는데, (팝업의 주최자마다 요구사항이 다른 점) 이부분을 모두 관리자가 처리하긴 어려울 것이니 이부분 보완 필요</li>
<li>개선사항으로 언급하긴했지만 줄을 다시 서는 기능이 있으면 좋을것같다</li>
<li>삭제한게 크롤링되면서 다시추가되는 현상이 있는데, 좋은 흐름은 아니다. 크롤링에서 제외하는 기능이라든지 있으면 좋을 것 같다.</li>
<li>길찾기는 사이트 내에서 하지않고 어플리케이션으로 이동해도 괜찮을 것 같다. 이미 잘 되어있고, 횟수가 넘어가면 요금이 부과된다.</li>
</ul>
<h3 id="동료-수강생-피드백">동료 수강생 피드백</h3>
<ul>
<li>이벤트 등록을 관리자계정에서만 해야하나? 라이트하게 열 수 있으니 이쪽으로도 접근해보면 좋을 것 같다.</li>
<li>사용자의 후기만 보여줄수있는 게시판이 있으면 좋을 것 같다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/0890676e-afb9-40e3-969f-3a24f157917c/image.png" alt=""></p>
<h3 id="결과">결과</h3>
<p>최우수팀 상을 받았습니다!! 회의하고 수정하고 회의하고 수정하고 *1000 했던 많은 시간들이 떠오르며 정말 감사하고 행복했습니다. 좋은 팀원들을 만나 여기까지 올 수 있었던 것 같아요. 더 개발하고싶었던 것들이 있었지만, 완성도를 위해 아쉽게 하지 못했던 것들도, 피드백받은 것들도 더 손보고싶습니다. 발표연습도 정말 여러 번 했는데 실수없이 잘 진행된 것 같아서 만족스러워요!</p>
<p><br><br><br></p>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[팀프로젝트 최종발표 D-1]]></title>
            <link>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B5%9C%EC%A2%85%EB%B0%9C%ED%91%9C-D-1</link>
            <guid>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B5%9C%EC%A2%85%EB%B0%9C%ED%91%9C-D-1</guid>
            <pubDate>Sun, 14 Jul 2024 12:57:29 GMT</pubDate>
            <description><![CDATA[<h3 id="진행상황">진행상황</h3>
<p>시연 DB 체크 및 정리본 만들기(노션, 발표스크립트 참고) 
=&gt; 체크리스트 만들고 발표때 진행 ✔️</p>
<p>포트폴리오 취합 및 정리 ✔️</p>
<p>일요일 19시 제출자료 정리 및 제출(WBS, 소스코드, /최종기획안, 포트폴리오, 발표ppt) - 구글드라이브 ✔️</p>
<p>MLP 개인제출자료 제출 ✔️</p>
<p>20시 발표시연 및 피드백 ✔️</p>
<hr>
<h3 id="발표전-사전확인">발표전 사전확인</h3>
<ul>
<li><p>시연에 필요한 데이터 미리 작성해놓고 복붙하며 시연</p>
</li>
<li><p>불필요한 예약 기록지우기</p>
</li>
<li><p>후기 여러개 등록해두기(삭제시연연습위해)</p>
</li>
<li><p>DB조작을 위해 디비버 켜두기</p>
</li>
<li><p>헬로키티 좋아요 제거 해놓기
(시연 시작 시점)</p>
</li>
<li><p>대기 데이터 작업</p>
</li>
</ul>
<pre><code class="language-sql">use hereevent;

insert into wait (event_no,wait_tel,email,wait_date,state) values 
(199,&#39;010-1111-1111&#39;,&#39;wefjnkf@example.com&#39;,NOW(),&#39;wait&#39;),
(199,&#39;010-1111-3333&#39;,&#39;fwef433@example.com&#39;,NOW(),&#39;wait&#39;),
(199,&#39;010-1111-4444&#39;,&#39;dfess2@example.com&#39;,NOW(),&#39;wait&#39;),
(199,&#39;010-1111-5555&#39;,&#39;asdf1234@example.com&#39;,NOW(),&#39;wait&#39;),
(199,&#39;010-1111-6666&#39;,&#39;r1d2s2@example.com&#39;,NOW(),&#39;wait&#39;),
(199,&#39;010-1111-2222&#39;,&#39;ggoing@example.com&#39;,NOW(),&#39;wait&#39;),
(199,&#39;010-1111-7777&#39;,&#39;seego21@example.com&#39;,NOW(),&#39;wait&#39;),
(199,&#39;010-1111-8888&#39;,&#39;sfe889@example.com&#39;,NOW(),&#39;wait&#39;),
(199,&#39;010-1111-9999&#39;,&#39;goodisalan@example.com&#39;,NOW(),&#39;wait&#39;),
(199,&#39;010-1111-1010&#39;,&#39;weiofg@example.com&#39;,NOW(),&#39;wait&#39;);

insert into wait (event_no,wait_tel,email,wait_date,state) values 
(179,&#39;010-1111-1232&#39;,&#39;1wngog@example.com&#39;,NOW(),&#39;wait&#39;),
(179,&#39;010-1111-3546&#39;,&#39;dfsdf55@example.com&#39;,NOW(),&#39;wait&#39;),
(179,&#39;010-1111-1422&#39;,&#39;erg154@example.com&#39;,NOW(),&#39;wait&#39;),
(179,&#39;010-4686-4965&#39;,&#39;454fjisd@gmail.com&#39;,NOW(),&#39;wait&#39;);</code></pre>
<ul>
<li><p>마이페이지에서 보여주며 순서 5번째일때 179번 대기 1번 cancel처리(90초가량 소요)</p>
</li>
<li><p>!!!!앞에 3명 남은 메일 오는거 보여줄때 모두 cancel처리</p>
</li>
<li><p>(관리페이지 이벤트 선택삭제) 이후 바로 관리자로그인-크롤링</p>
</li>
</ul>
<h3 id="소감">소감</h3>
<ul>
<li>발표에 대한 모든 준비를 마치고, 시연하며 발표준비의 완벽도를 높이는 연습을 하고있다.</li>
<li>필요한 제출자료를 모두 제출하고 발표만을 앞두니 정말 시원섭섭한 느낌이 든다.</li>
<li>발표를 하면서 발표자를 뒷받침해주기 위해 화면을 조작해주는 일, 여러 경우의 수를 보여주기 위해 타이밍에 맞추어 DB를 조작하는 일 등을 준비하는게 왠지 재미있다.</li>
<li>몇 달 동안 우리를 이끌어주신 강사님과 함께 작업하고 공부한 동료수강생들과 이별하는게 아직 실감이 안난다 ㅜㅜ 언젠가 다시 마주할 날이 오길..~~</li>
</ul>
<p><br><br><br><br>
본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[팀프로젝트 발표 D-2]]></title>
            <link>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B0%9C%ED%91%9C-D-</link>
            <guid>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B0%9C%ED%91%9C-D-</guid>
            <pubDate>Sat, 13 Jul 2024 08:26:26 GMT</pubDate>
            <description><![CDATA[<h3 id="주말-개인-과업-리스트업">주말 개인 과업 리스트업</h3>
<ul>
<li><p>발표 시연 피드백 ✔️</p>
</li>
<li><p>멘토님 피드백 정리 ✔️</p>
</li>
<li><p>영상편집 마무리 ✔️</p>
</li>
<li><p>영상편집 피드백 후 통합 ✔️</p>
</li>
<li><p>시연영상 구글드라이브 제출 ✔️</p>
</li>
<li><p>유튜브 채널 개설 및 영상 업로드 ✔️
<a href="https://www.youtube.com/watch?v=EFXo2e9CUlE">HereEvent 시연영상</a></p>
</li>
</ul>
<ul>
<li><p>시연 DB 체크 및 정리본 만들기(노션, 발표스크립트 참고)</p>
</li>
<li><p>포트폴리오 취합 및 정리 =&gt; 체크리스트 만들고 발표때 진행</p>
</li>
<li><p>일요일 19시 제출자료 정리 및 제출(WBS, 소스코드, /최종기획안, 포트폴리오, 발표ppt) - 구글드라이브</p>
</li>
<li><p>MLP 개인제출자료 제출</p>
</li>
<li><p>20시 발표시연 및 피드백 </p>
</li>
</ul>
<hr>
<h3 id="발표시-참고할-피드백">발표시 참고할 피드백</h3>
<ul>
<li><p>ppt발표와 시연시간 비중 2:1~ 3:1(시연은 최대 10분 내외)</p>
</li>
<li><p>입력데이터 있는 경우 미리 써놓기</p>
</li>
<li><p>시연데이터 미리 db에 준비해두기</p>
</li>
<li><p>마이크와 발표톤 듣기 편하게 진행</p>
</li>
<li><p>주요기능 위주로 발표, 수정/삭제/목록보기 등 중복사항은 생략</p>
</li>
</ul>
<p><br><br><br>
본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[팀프로젝트 D-3]]></title>
            <link>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-D-3</link>
            <guid>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-D-3</guid>
            <pubDate>Fri, 12 Jul 2024 05:11:57 GMT</pubDate>
            <description><![CDATA[<h3 id="오늘-수행내용">오늘 수행내용</h3>
<ul>
<li>발표 구성 및 순서 정하기</li>
<li>수행일지 작성 및 업로드</li>
<li>강사님 피드백 &amp; 피드백 내용 정리(노션 및 수행일지에 작성)</li>
<li>시연영상편집</li>
<li>시연영상 편집본 피드백</li>
<li>추가녹화 내용 : 이벤트 추천 이메일, 관리 메인페이지, 관리 목록 2개 추가내역, 크롤링, 예약당일 입장/취소버튼 뜨는 부분</li>
<li>크롤링된 DB 이벤트테이블 작업</li>
<li>회원 이미지 저장경로 오류 수정</li>
<li>jar파일 서버 업데이트</li>
</ul>
<br>

<h3 id="오늘의-생각">오늘의 생각</h3>
<ul>
<li><p>중간중간 적재적소에 역할을 분담하여 막힘없이 잘 흘러가는 듯 하다.</p>
</li>
<li><p>어제 뽑기로 정한 프로젝트 발표 순서와 발표당일 시간표가 오늘 업로드되었다. 시간표만 봐도 너무 떨린다... 주말엔 멘토님께 피드백받고 시연연습을 반복하는 일만 남았다..!!! </p>
</li>
<li><p>강의 듣는 동안 하루도 온전히 쉰 날이 없을 만큼 달려오기도 했고, 주말없이 진행한 한달 반 가량의 프로젝트도 준비한대로 마무리가 되어가니 너무 뿌듯하고 기분이 좋다! 중간중간 정리하고 회의하고 하는 과정이 피로하게 느껴질 때도 있었지만, 그 작업을 계속 해준 덕에 계획에서 크게 어긋나지 않고 마무리되어간다고 생각한다.</p>
</li>
<li><p>욕심나는 부분도 있었지만, 전반적인 완성도를 위하여 가져갈부분을 초반부터 확실히 정하고 우선순위대로 작업하는게 단기 프로젝트에서는 무엇보다 중요한 것 같다. 멘토님과 강사님의 피드백 덕이다!!  </p>
</li>
<li><p>프로젝트동안 가끔 시간을 써서 열심히 작업한 부분을 버리고 새로 작업해야하는 순간들이 있었다. 나 말고도 다른 분들도 마찬가지였다. 그럴때 당연히 아쉬운 마음이 들지만, 강의를 듣기 전 많이 들은 고인물 개발자들의 조언이 떠오른다. 진짜 잘하는 개발자는 자기가 쓴 코드에 집착하지 않는다는 말.. 그 생각을 하며 아쉬움은 빠르게 털어내고 목표에 도달하는 데에 가까운 방식을 채택하는 방법을 체득할 수 있었던 것 같다.</p>
</li>
<li><p>우리 팀이 만든 프로젝트에 애착이 생기는 만큼, 다른 조들도 자식같은(?ㅋㅋ) 프로젝트를 만들어냈을텐데 너무 궁금하고 기대된다!!</p>
</li>
<li><p>발표날까지 아자아자 팟팅이다<del>~</del>!!!!</p>
</li>
</ul>
<p><br><br><br>
본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[팀프로젝트 D-4]]></title>
            <link>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-D-4</link>
            <guid>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-D-4</guid>
            <pubDate>Wed, 10 Jul 2024 15:42:16 GMT</pubDate>
            <description><![CDATA[<p>이번주엔 자잘한 프론트 문제나 사용자 측면에서 있으면 좋을 것 같은 것들을 보완하고 수정했다. 그리고 최종 프로젝트에서 사용할 DB를 조직화하고 준비했다.</p>
<p>다른 데이터는 그냥 삽입해두면 되는데 시간에 따라 데이터가 변경되는 예약과 대기기능은 데이터를 어떻게 해야할지 고민이 조금 길어졌었다.
결국 특정 이벤트를 정하여 시연 이전에 추가하는 방식을 사용하기로 했다.
예약은 시연날짜를 기준으로 다시 정리하여 올려야 한다.</p>
<p>서버에 배포하는 과정에서는 큰 어려움이 없을줄로만 알았는데, 계획보다 이르게 주말에 서버를 생성하고 배포해보길 잘했다.
http환경에서 되지 않는 작업들이 은근 있었던것.. 내위치를 가져오는  기능도 https환경에서만 가능하고 길찾기 기능도 문제가 생겨서 담당하신 분이 2-3일 고생했었다.
그외에도 지도, 소셜로그인 등의 ip주소를 변경하는 등 생각보다 여러 작업들이 필요했다.</p>
<p>미리 준비해도 빠듯하게 느껴지는 시간들..! 그 와중에 시간 앞당겨서 한게 얼마나 다행으로 여겨지던지..</p>
<p>어제오늘까지 작업한 기능들 정리하고 오늘부터는 거의 다 준비된 데이터와 기능들을 바탕으로 화면녹화를 뜨고 내일부터는 시연영상 편집을 하려고 한다.
<img src="https://velog.velcdn.com/images/brave_chicken/post/c0715a0f-730e-4bb7-980e-26b78c530dc9/image.png" alt=""></p>
<p>중간중간 회의하고 의견 나눌 것이 계속 생긴다. 또 잘하고싶은 욕심과 가끔 느껴지는 벽들에 조금은 지치기도 했던 요며칠이었지만..! 
그래도 작업했던 것들 정리하고 또 하나하나씩 개선되어가는 것들을 보며 다시 힘을 얻는다.</p>
<p>꾸준히 올려오던 벨로그를 드문드문 올리게 되어 조금은 아쉽지만 ㅜ 그래도 남은 시간 틈틈이 더 기록해볼수있길..!</p>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네이버클라우드 서버 배포]]></title>
            <link>https://velog.io/@brave_chicken/%EB%84%A4%EC%9D%B4%EB%B2%84%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EC%84%9C%EB%B2%84-%EB%B0%B0%ED%8F%AC</link>
            <guid>https://velog.io/@brave_chicken/%EB%84%A4%EC%9D%B4%EB%B2%84%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EC%84%9C%EB%B2%84-%EB%B0%B0%ED%8F%AC</guid>
            <pubDate>Wed, 10 Jul 2024 15:29:42 GMT</pubDate>
            <description><![CDATA[<p>네이버클라우드 사용</p>
<ol>
<li>intelliJ에서 jar파일 생성
Gradle - task - build - bootJar
<img src="https://velog.velcdn.com/images/brave_chicken/post/75bcbae9-de93-4a93-ab65-8da115b13ea8/image.png" alt=""></li>
</ol>
<p>물리적경로 확인
<img src="https://velog.velcdn.com/images/brave_chicken/post/79c10d67-ade7-423e-bc42-ef15ec68f6cb/image.png" alt=""></p>
<ol start="2">
<li>cmd창에서 위치이동<pre><code>C:\Users\주희&gt;cd C:\backend23\work\team_pro\build\libs</code></pre></li>
</ol>
<pre><code>C:\backend23\work\team_pro\build\libs&gt;scp ./hereevent-0.0.1-SNAPSHOT.jar root@223.130.158.5:/root/upload
root@223.130.158.5&#39;s password:
hereevent-0.0.1-SNAPSHOT.jar   </code></pre><p>로그인 root로 하고
<img src="https://velog.velcdn.com/images/brave_chicken/post/c88d98ec-a725-4d99-8976-e73c75755451/image.png" alt="">
하면 서버스타트됨</p>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[redis 특강]]></title>
            <link>https://velog.io/@brave_chicken/240703</link>
            <guid>https://velog.io/@brave_chicken/240703</guid>
            <pubDate>Mon, 08 Jul 2024 05:03:43 GMT</pubDate>
            <description><![CDATA[<h3 id="buildgradle">build.gradle</h3>
<pre><code>dependencies {
    implementation &#39;org.springframework.boot:spring-boot-starter-data-jpa&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-data-redis&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-thymeleaf&#39;
    implementation group: &#39;org.modelmapper&#39;, name: &#39;modelmapper&#39;, version: &#39;2.4.0&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-web&#39;
    compileOnly &#39;org.projectlombok:lombok&#39;
    developmentOnly &#39;org.springframework.boot:spring-boot-devtools&#39;
    runtimeOnly &#39;com.oracle.database.jdbc:ojdbc11&#39;
    annotationProcessor &#39;org.projectlombok:lombok&#39;
    testImplementation &#39;org.springframework.boot:spring-boot-starter-test&#39;
    testRuntimeOnly &#39;org.junit.platform:junit-platform-launcher&#39;
}</code></pre><h3 id="applicationproperties">application.properties</h3>
<pre><code>spring.application.name=erp
server.port=8088


#db ??? ?? ??
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@127.0.0.1:1521:xe
spring.datasource.username=test
spring.datasource.password=test

#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.url=jdbc:mysql://db-nt04n-kr.vpc-pub-cdb.ntruss.com:3306/myerp?serverTimezone=UTC
#spring.datasource.username=myerp
#spring.datasource.password=myerp2024!

#mybatis ??? ?? ??
mybatis.mapper-locations=classpath:/mapper/*.xml
mybatis.type-aliases-package=com.example.erp.dto

#redis
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
#spring.data.redis.password=

#jpa????
#???? ??? ???? ?????. drop ??? ???? create
#spring.jpa.hibernate.ddl-auto=create
spring.jpa.hibernate.ddl-auto=none
spring.sql.init.encoding=UTF-8
spring.sql.init.mode=always


#sysout?? ??
spring.jpa.show-sql=true

#JPA log
#??????? ???? ???? sql??
logging.level.org.hibernate.sql=debug
logging.level.org.hibernate.type.descriptor.sql=trace

#JPA? ???? sql? ??? ????
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true

jpa.defer-datasource-initialization=true</code></pre><p><img src="https://velog.velcdn.com/images/brave_chicken/post/85855a9b-d255-4124-bbfd-7405dcc73a4d/image.png" alt=""></p>
<h2 id="config">config</h2>
<h3 id="redisconfig">RedisConfig</h3>
<pre><code class="language-java">@Configuration
public class RedisConfig {
    @Value(&quot;${spring.data.redis.host}&quot;)
    private String host;
    @Value(&quot;${spring.data.redis.port}&quot;)
    private int port;
    /*@Value(&quot;{spring.data.redis.password}&quot;)
    private String password;*/

    //LettuceConnectionFactory는 Redis서버와 연결을 설정하고 관리하는 객체
    //이를 통해서 spring data redis내부에서 redis서버와 통신할 ㅅ 있다.
    @Bean
    public RedisConnectionFactory redisConnectionFactory(){
        //config객체를 만들고
        RedisStandaloneConfiguration config =
                new RedisStandaloneConfiguration(host,port);
        //config.setPassword(password);

        //config를 이용해서 factory객체를 만들어서 리턴
        return new LettuceConnectionFactory(config);
    }

    @Bean
    @Primary //빈을 만들때 우선순위 높게 지정
    public RedisTemplate&lt;String,String&gt; redisTemplate(){
        RedisTemplate&lt;String,String&gt; redisTemplate = new RedisTemplate&lt;&gt;();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        //hashes operation을 사용하는 경우
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());

        return redisTemplate;
    }
}</code></pre>
<h2 id="hashes">hashes</h2>
<h3 id="subject">Subject</h3>
<ul>
<li>@RedisHash : redis에 저장할 클래스를 생성</li>
<li>value는 redis에 들어갈 객체의 key가 된디</li>
<li>키는 value에 지정한 key:entityid
=&gt;mysubject : id<pre><code class="language-java">@Data
@NoArgsConstructor
@AllArgsConstructor
@RedisHash(value = &quot;mysubject&quot;)
public class Subject {
  @Id
  private String id;
  private String name;
  private int price;
  private String info;
}
</code></pre>
</li>
</ul>
<pre><code>
### SubjectHashController
```java
@RestController
@RequiredArgsConstructor
public class SubjectHashController {
    private final SubjectHashService service;
    //request용 response용 dto는 따로 만들어서 작업하기
    //redis에 저장하기
    @PostMapping(&quot;/hashtest&quot;)
    public Subject save(@RequestBody Subject subject){
        System.out.println(subject);
        return service.save(subject);
    }

    //redis에 저장된 데이터 불러오기
    @GetMapping(&quot;/hashtest&quot;)
    public Subject find(@RequestParam(&quot;id&quot;) String id){
        return service.findById(id);
    }
}
</code></pre><h3 id="subjecthashrepository">SubjectHashRepository</h3>
<pre><code class="language-java">public interface SubjectHashRepository extends CrudRepository&lt;Subject,String&gt; {
}</code></pre>
<h3 id="subjecthashservice">SubjectHashService</h3>
<pre><code class="language-java">public interface SubjectHashService {
    Subject save(Subject subject);
    Subject findById(String id);

}</code></pre>
<h3 id="subjecthashserviceimpl">SubjectHashServiceImpl</h3>
<pre><code class="language-java">@Service
@RequiredArgsConstructor
public class SubjectHashServiceImpl implements SubjectHashService{
    private final SubjectHashRepository repository;

    @Override
    public Subject save(Subject subject) {
        return repository.save(subject);
    }

    @Override
    public Subject findById(String id) {
        return repository.findById(id).get();
    }
}
</code></pre>
<h2 id="sortedset">sortedset</h2>
<h3 id="product">Product</h3>
<pre><code class="language-java">@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
    private String categoryId;//key
    private String productId;//member(sortedset에 저장되는 각 요소)
    private int price;//score
}</code></pre>
<h3 id="sortedsetcontroller">SortedSetController</h3>
<pre><code class="language-java">@RestController
@RequiredArgsConstructor
public class SortedSetController {
    private final SortedSetService service;

    @GetMapping(&quot;/getzset&quot;)
    public Set&lt;ZSetOperations.TypedTuple&lt;String&gt;&gt; getzsetvalues(@RequestParam(&quot;key&quot;) String key){
        return service.getZsetValues(key);
    }

    @PostMapping(&quot;/add&quot;)
    public int create(@RequestBody Product newProduct){
        service.createMember(newProduct);
        return service.getRank(newProduct);
    }
}</code></pre>
<h3 id="sortedsetservice">SortedSetService</h3>
<pre><code class="language-java">public interface SortedSetService {
    //전체 sorted set의 멤버들 조회
    //ZSetOperations은 sortedset을 다루기 위해 여러가지 메소드를 제공하는 인터페이스
    //TypedTuple은 spring data redis에서 제공하는 인터페이스 - sortedset의 자료구조를 모델링한 객체
    Set&lt;ZSetOperations.TypedTuple&lt;String&gt;&gt; getZsetValues(String key);
    //새로운 member를 저장
    void createMember(Product newProduct);
    //매개변수로 정의한 상품의 rank구하기
    int getRank(Product newProduct);
}</code></pre>
<h3 id="sortedsetserviceimpl">SortedSetServiceImpl</h3>
<pre><code class="language-java">@Service
@RequiredArgsConstructor
public class SortedSetServiceImpl implements SortedSetService{
    private final RedisTemplate&lt;String,String&gt; redisTemplate;

    //sortedset에 저장된 모든 member와 score를 조회
    @Override
    public Set&lt;ZSetOperations.TypedTuple&lt;String&gt;&gt; getZsetValues(String key) {
        ZSetOperations&lt;String,String&gt; zSetOperations = redisTemplate.opsForZSet();
        Set&lt;ZSetOperations.TypedTuple&lt;String&gt;&gt; sortedset = zSetOperations.rangeWithScores(key,0,-1);
        return sortedset;
    }

    @Override
    public void createMember(Product newProduct) {
        ZSetOperations&lt;String,String&gt; zSetOperations = redisTemplate.opsForZSet();
        //key,member,score
        zSetOperations.add(newProduct.getCategoryId(),
                newProduct.getProductId(), newProduct.getPrice());
    }

    //정의한 객체의 순위를 리턴
    @Override
    public int getRank(Product newProduct) {
        ZSetOperations&lt;String,String&gt; zSetOperations = redisTemplate.opsForZSet();
        int rank = zSetOperations.rank(newProduct.getCategoryId(),
                newProduct.getProductId()).intValue();
        return rank;
    }
}
</code></pre>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/56f70872-9bbe-4f48-88ca-d88a85db7924/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/4777a52b-189b-4fe0-b6c5-e9709e608866/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/63dd2e2e-5bb7-4a11-9ef6-511cd1204377/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/bafd3751-d80d-4648-83ec-edb4a4371c7e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/cd01b0ed-f8b4-4d0d-b932-6eaef65c0298/image.png" alt=""></p>
<pre><code>C:\Users\주희&gt;cd\

C:\&gt;cd C:\Program Files\Redis

C:\Program Files\Redis&gt;redis-cli

127.0.0.1:6379&gt; keys *
1) &quot;cate001&quot;
2) &quot;mysubject&quot;
3) &quot;mysubject:subject02&quot;
4) &quot;test1&quot;
5) &quot;mysubject:subject01&quot;

127.0.0.1:6379&gt; zrange cate001 0 -1
1) &quot;prd02&quot;

127.0.0.1:6379&gt; zrange cate001 0 -1
1) &quot;prd01&quot;
2) &quot;prd03&quot;
3) &quot;prd02&quot;</code></pre><p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[팀프로젝트 D-13 ]]></title>
            <link>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-D-13</link>
            <guid>https://velog.io/@brave_chicken/%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-D-13</guid>
            <pubDate>Tue, 02 Jul 2024 09:08:10 GMT</pubDate>
            <description><![CDATA[<h1 id="남은기능">남은기능</h1>
<h3 id="⇒-이번-주-안으로-끝내기1차-마감-금요일-2차-마감-일요일">⇒ 이번 주 안으로 끝내기(1차 마감 금요일, 2차 마감 일요일)</h3>
<ul>
<li><p><strong>관리자페이지</strong>(후기 form참고)</p>
<ul>
<li>이벤트관리</li>
<li>회원관리</li>
<li>후기관리(선택 삭제만 남음)</li>
<li>관리자 메인 페이지 차트 (날짜별 등록 회원 수, 날짜별 오픈 이벤트, …)</li>
</ul>
</li>
<li><p><strong>이메일 보내기</strong> (예약, 대기 관련)</p>
</li>
<li><p><strong>상세페이지</strong></p>
<ul>
<li><p>달력 마무리</p>
</li>
<li><p>길찾기</p>
<p>  <a href="https://lab.odsay.com/">ODsay LAB</a></p>
</li>
</ul>
</li>
<li><p><strong>지도</strong> (마커-목록 싱크맞추기)</p>
</li>
<li><p><strong>기타 기능</strong></p>
<ul>
<li>해시태그 크롤링</li>
<li>문자 보내기</li>
</ul>
</li>
<li><p><strong>프론트엔드 보완</strong></p>
<ul>
<li>메인배너</li>
<li>기타 프론트 보완 및 추가 필요</li>
<li>상세페이지</li>
<li>대기페이지</li>
<li>카테고리별 목록(4개씩 출력)</li>
</ul>
</li>
<li><p><strong>파일정리</strong></p>
<ul>
<li>컨트롤러 분리</li>
<li>css, js파일 분리</li>
</ul>
</li>
</ul>
<p><br/><br/><br/></p>
<h1 id="마지막-주-타임-라인">마지막 주 타임 라인</h1>
<ul>
<li><strong>포트폴리오 자료정리</strong><ul>
<li>기한 : ~ 수요일까지</li>
<li>양식 있는지 확인/ 매니저님께 요청</li>
<li>참고방향 : 사이트의 차별성과 필요성 설득력있게 기술, 다함께 중간점검으로 수정/보완작업하기</li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>시연동영상 녹화, 편집</strong></p>
<ul>
<li>기한 : ~금요일</li>
<li>멘토님 피드백 후 한번 더 보완</li>
</ul>
</li>
<li><p><strong>포트폴리오 디자인</strong></p>
<ul>
<li>기한 : ~금요일</li>
</ul>
</li>
<li><p><strong>서버 등록</strong></p>
<ul>
<li>기한 : ~수요일</li>
</ul>
</li>
<li><p><strong>기획안 수정</strong></p>
<ul>
<li>기한 : ~수요일</li>
</ul>
</li>
<li><p><strong>db 자료 등록</strong> : 회원(등록날짜 6-7월 사이 다양하게), 리뷰, 예약/대기, …</p>
<ul>
<li>기한 : ~수요일</li>
</ul>
</li>
<li><p><strong>발표</strong></p>
<ul>
<li>기한 : 토~일</li>
<li>준비방향 : 대본 각자 준비(~토요일), 최소 3회 이상 시연 및 피드백 진행, 일요일 최종 시연 후 마무리, 가능하면 멘토님 앞에서 1회라도 시연하기</li>
<li>파트 : 마이페이지, 관리자페이지, 상세페이지, 메인페이지, 지도페이지 </li>
</ul>
</li>
</ul>
<p><br/><br/></p>
<h3 id="기록">기록</h3>
<ul>
<li>발표가 2주 앞으로 다가와서 남은 시간을 어떻게 보낼지 회의를 함.</li>
<li>기능들이 거의 마무리되어가기에 초반에 나눈 기능별 역할분담을 다시 업데이트할 필요가 있다고 느낌.</li>
<li>자신이 원하는 파트, 남은 시간 필요한 파트 등을 반영하여 다시 역할분담함.</li>
<li>멘토님도 강사님도 중요하다고 생각하시는 기능에 차이가 조금은 있어, 여러 관점을 반영하여 남은 시간을 세팅하도록 함.</li>
<li>발표준비와 개발의 완성도있는 마무리를 위해 의미있는 시간이었다고 느낌!</li>
<li>역할분담을 하며 느낀거지만, 우리 팀원들은 다 배울 점이 있는 것 같아 감사함을 느낌!</li>
</ul>
<p><br/><br/><br/></p>
<h3 id="-출석률">+ 출석률</h3>
<p>출석은 당연한거지만.. 총 일수가 되어갈수록 빽빽한 진행률이 날 기분 좋게 만든다!
<img src="https://velog.velcdn.com/images/brave_chicken/post/28bcdbd9-642d-434b-9e8d-53de422eb632/image.png" alt=""></p>
<p><br/><br/><br/><br/><br/></p>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redis 특강]]></title>
            <link>https://velog.io/@brave_chicken/Redis-%ED%8A%B9%EA%B0%95</link>
            <guid>https://velog.io/@brave_chicken/Redis-%ED%8A%B9%EA%B0%95</guid>
            <pubDate>Tue, 02 Jul 2024 02:46:54 GMT</pubDate>
            <description><![CDATA[<p><a href="https://github.com/microsoftarchive/redis/releases">redis 다운로드</a></p>
<p><a href="https://redis.io/">redis.io</a>
<img src="https://velog.velcdn.com/images/brave_chicken/post/dd1d0e75-6f1c-4ec3-8faf-3972358ac403/image.png" alt=""></p>
<h3 id="1-string">1. String</h3>
<p>단일값저장</p>
<blockquote>
<p>set key
get key</p>
</blockquote>
<h3 id="2-sortedset">2. SortedSet</h3>
<p>ZSet이라고도 한다.
저장된 데이터를 유니크하게 관리하기 위해서 사용</p>
<h4 id="1-zadd">1) zadd</h4>
<blockquote>
<p>zadd key score member</p>
</blockquote>
<ul>
<li>key : sortedset의 이름</li>
<li>score : 각 요소에 할당된 점수</li>
<li>member : 각 요소의 이름(값)</li>
</ul>
<h4 id="2-zrange">2) zrange</h4>
<p>정렬된 원소에서 내가 출력하고 싶은 start번호 end번호
첫번째요소가 0
마지막요소가 -1
<img src="https://velog.velcdn.com/images/brave_chicken/post/f0b33f9b-6993-4800-bdda-793562f36fb0/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/90499cb5-8d5e-46e9-8888-75a9f90baff9/image.png" alt=""></p>
<h4 id="3-zrem">3) zrem</h4>
<p>삭제</p>
<h4 id="4-zrangebyscore">4) zrangebyscore</h4>
<blockquote>
<p>zrangebyscore key min max</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/0288a992-94d9-4302-a9ca-959dbf795274/image.png" alt=""></p>
<blockquote>
<p>zrangebyscore key (min(max</p>
</blockquote>
<p>=&gt; min초과 max미만
<img src="https://velog.velcdn.com/images/brave_chicken/post/05dd52fb-4b9e-4cfb-a959-3d1bbb7b7e0b/image.png" alt=""></p>
<h4 id="5-zrevrangebyscore">5) zrevrangebyscore</h4>
<blockquote>
<p>zrevrangebyscore myset1 +inf (20000 withscores</p>
</blockquote>
<p>20000보다 높은 score의 member들을 조회</p>
<h4 id="6-zscore">6) zscore</h4>
<blockquote>
<p>zscore key member</p>
</blockquote>
<p>지정한 member에 대한 score를 조회</p>
<h4 id="7-zrank">7) zrank</h4>
<blockquote>
<p>zrank key member</p>
</blockquote>
<p>해당 member의 순위 조회</p>
<h3 id="실습">실습</h3>
<p>key =&gt; myboard</p>
<h4 id="1-게시글과-조회수를-sortedset에-저장">1. 게시글과 조회수를 sortedset에 저장</h4>
<p>5개를 임의로 저장
조회수와 게시글번호
<img src="https://velog.velcdn.com/images/brave_chicken/post/e419fc42-4ab6-42ff-af6b-2949b74ad7e2/image.png" alt=""></p>
<h4 id="2-전체글과-조회수를-모두-조회">2. 전체글과 조회수를 모두 조회</h4>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/f146d276-b411-493a-af9b-38226742c4ce/image.png" alt=""></p>
<h4 id="3-조회수가-가장-많은-글-조회">3. 조회수가 가장 많은 글 조회</h4>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/13e47e3b-a28c-47e2-b077-8002292994c4/image.png" alt=""></p>
<h4 id="4-1위의-게시글-조회">4. 1위의 게시글 조회</h4>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/81085300-ab46-4175-b80c-462554d2d647/image.png" alt=""></p>
<hr>
<p><br/><br/><br/><br/><br/></p>
<h3 id="hash">hash</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/946f2497-889c-4ded-88d7-11a55179b5cb/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/e61fd9dc-0a94-4997-8fc2-0834840c67f5/image.png" alt=""></p>
<h3 id="실습-1">실습</h3>
<p>BoardDTO의 모든 값을 hashes로 저장하기
myboardhash</p>
<h3 id="redis-intellij프로젝트-만들기">redis intelliJ프로젝트 만들기</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/7c6e06b1-adbe-4c89-a716-5ceffad8c910/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/d5136459-65ef-4485-85a7-1da0405125cf/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/0b8edaa9-00df-46e1-a2a4-91dea5dd0cd7/image.png" alt=""></p>
<p><br/><br/><br/><br/><br/>
본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[팀프로젝트 기록]]></title>
            <link>https://velog.io/@brave_chicken/240701-%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B8%B0%EB%A1%9D</link>
            <guid>https://velog.io/@brave_chicken/240701-%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B8%B0%EB%A1%9D</guid>
            <pubDate>Mon, 01 Jul 2024 10:47:34 GMT</pubDate>
            <description><![CDATA[<p>이제 팀프로젝트가 딱 2주 남았다.
웬만한 우선순위의 기능들은 거의 다 개발했고, 보수작업을 하며 발표를 슬슬 준비해야하는 시기이다.</p>
<p>토요일에 받은 멘토링을 바탕으로 우선순위를 재분류하고 남은 일들을 효율적으로 재구성하며 마무리를 하고있다.</p>
<p>오늘 했던 작업은 크게 메인페이지(index)에 피드백을 바탕으로 추가적인 효과를 주는 작업과 이벤트 목록 페이지를 보수하는 작업 두개로 분류할 수 있다.
<br/></p>
<h4 id="메인페이지-작업">메인페이지 작업</h4>
<ul>
<li>autoplay 효과가 없애기</li>
<li>loop 없애기</li>
<li>순위가 있는 목록에 순위 표시하기</li>
<li>목록별로 제목 누르면 이벤트 카드목록으로 볼 수 있게 연결하기</li>
<li>카테고리만 목록의 양식이 달랐는데 통일하기</li>
<li>hover시에 이벤트 정보(이벤트 이름, 별점, 기간 등) 보이게 하기 </li>
<li>넘치는 글자는 한 줄로 자르고 생략문자 주기</li>
</ul>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/09c05045-440f-480d-afbc-20c63db60c4e/image.png" alt="">
<br/></p>
<h4 id="메인페이지-작업-중-생긴-문제">메인페이지 작업 중 생긴 문제</h4>
<ul>
<li>hover 효과를 주니 태그 안에 주었던 onclick이 작동하지 않음
=&gt; pointer-events: auto; 와 z-index: 2;를 주어도 해결되지 않음
(아마 js코드가 아닌 태그 안에 준 onclick이라 그런듯)
=&gt; hover하는 태그에 이미지 태그에 있던 onclick을 주니 다시 작동함</li>
<li>순위를 어떻게 줄지 고민
<img src="https://velog.velcdn.com/images/brave_chicken/post/88fee67d-411e-4895-b34f-cbca9c057706/image.png" alt="">
each에 i를 부여하고 0부터 나오는 index에 1을 추가하고 문자인 &quot;위&quot;를 옆에 추가함</li>
<li>목록이 뜨지 않아서 mapper에 있는 sql문을 수정<br/>
#### 목록페이지 작업</li>
<li>피드백대로 기간을 추가하고 정렬과 텍스트 배치 수정</li>
<li>검색 목록화면과 카테고리 목록화면도 함께 수정</li>
<li>상단바 추가하기</li>
<li>지도 마커 닫기표시랑 제목이 겹치지 않게 수정
<img src="https://velog.velcdn.com/images/brave_chicken/post/64a2d02f-859f-46ba-8ce8-bbd471485765/image.png" alt=""></li>
</ul>
<br/>

<h4 id="참고했던-글">참고했던 글</h4>
<p><a href="https://velog.io/@parkheeyeun/%EC%9D%B4%EB%AF%B8%EC%A7%80-hover-%EA%B8%80%EC%9E%90">이미지 hover시 글자표시</a></p>
<p><a href="https://juni-official.tistory.com/172">글자수 초과시 생략문자주기</a></p>
<p><br/><br/><br/><br/><br/>
본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[240627 팀프로젝트 기록]]></title>
            <link>https://velog.io/@brave_chicken/240627-%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B8%B0%EB%A1%9D</link>
            <guid>https://velog.io/@brave_chicken/240627-%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B8%B0%EB%A1%9D</guid>
            <pubDate>Thu, 27 Jun 2024 08:12:28 GMT</pubDate>
            <description><![CDATA[<h3 id="웹소켓-선택수업-진행">웹소켓 선택수업 진행</h3>
<p>다대다 채팅 그룹채팅 관련하여 수업진행함
<img src="https://velog.velcdn.com/images/brave_chicken/post/c80309f1-e4e7-45db-858f-dabb219d6bbb/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/5635eddc-5fd6-48e2-88eb-4cff1e78f60b/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/9d1562a1-213e-4570-8970-5b3840c9a9fa/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/9f207e95-d6c0-43a2-80ed-b5236aa064d0/image.png" alt=""></p>
<h3 id="중간점검-및-논의">중간점검 및 논의</h3>
<ul>
<li>팀프로젝트 기능개발은 막바지로 향해서 마무리작업과 보충이 필요한 부분을 각자 공유함 
: 프론트를 사용자측면에서 작업하기 위한 고민을 멘토링때 나누기로함</li>
<li>내일 주간일지 제출을 위해 한주 각자 작업했던 내용과 다음주 계획을 공유하고 역할재분배를 함</li>
<li>어려움이 있는 부분을 공유하고, 서로가 도와줄 수 있는 지점을 체크함</li>
<li>내일 멘토링 이전 점검을 위한 피드백 시간을 강사님께 요청함</li>
</ul>
<h3 id="팀프로젝트-진행하며-배운-기능-일부">팀프로젝트 진행하며 배운 기능 일부</h3>
<ul>
<li>dto 파라미터를 ajax로 넘기는 방법을 배웠음.. 이부분 팀프로젝트 기간 중 제일 오랜시간 할애함</li>
<li>부트스트랩 샘플을 수정하는 과정에서 css가 잘 적용되지 않는 부분이 있었음. jquery로 생성하는 부분이라 잘 되지 않았는지.. 이부분 body에 삽입하는 div태그에 id를 주어 해결함</li>
<li>db데이터를 jquery로 넘기는 게 익숙하지 않았지만 하다보니 적응할 수 있었음</li>
</ul>
<h3 id="팀프로젝트-및-과정-종료를-3주정도-앞두고">팀프로젝트 및 과정 종료를 3주정도 앞두고..</h3>
<ul>
<li>주변의 도움을 받기도 하고, 가끔은 주기도 하는 과정이 재밌고 보람참</li>
<li>역시 직접 해보고 고민하고 해결하는게 제일 재밌음</li>
<li>도움을 청할 수 있는 팀원, 강사님, 멘토님이 있는 게 감사한 나날..~</li>
<li>과정 시작부터 중간과정 중 팀 내에서도 피드백과 계획재수립이 계속 오가기도 하지만, 주간일지, 멘토링, 피드백시간 등이 주기적으로 있어서 늘어지지않고 템포를 유지할 수 있는 것 같다</li>
<li>만족할만한 마무리를 위해서.. 남은 시간도 아자아자 팟팅이다~!</li>
</ul>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹소켓 채팅 추가 : 서버 시연, 사진보내기]]></title>
            <link>https://velog.io/@brave_chicken/240625</link>
            <guid>https://velog.io/@brave_chicken/240625</guid>
            <pubDate>Tue, 25 Jun 2024 08:56:59 GMT</pubDate>
            <description><![CDATA[<h2 id="서버-웹소켓">서버 웹소켓</h2>
<h3 id="서버에-등록배포하여-동시접속-시연해보기">서버에 등록/배포하여 동시접속 시연해보기</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/0e6fc8ea-695d-4281-9c55-cd14871aaa91/image.png" alt=""></p>
<h2 id="웹소켓-사진전송">웹소켓 사진전송</h2>
<h3 id="websocketcontroller">WebSocketController</h3>
<pre><code class="language-java">@Controller
public class WebSocketController {
    @GetMapping(&quot;/chat&quot;)
    public String showview(){
        return &quot;chat&quot;;
    }
    @GetMapping(&quot;/chat2&quot;)
    public String showView2() {
        System.out.println(&quot;컨트롤러&quot;);
        return &quot;chatt2&quot;;
    }
}</code></pre>
<h3 id="mybinaryhandler">MyBinaryHandler</h3>
<pre><code class="language-java">@Component
public class MyBinaryHandler extends TextWebSocketHandler{
    HashMap&lt;String, WebSocketSession&gt; sessionMap = new HashMap&lt;&gt;(); //웹소켓 세션을 담아둘 맵
    private static final String FILE_UPLOAD_PATH = &quot;C:\\chat&quot;;
    static int fileUploadIdx = 0;
    static String fileUploadSession = &quot;&quot;;

    //소켓연결
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // TODO Auto-generated method stub
        super.afterConnectionEstablished(session);
        System.out.println(&quot;연결&quot;);
        sessionMap.put(session.getId(), session);
    }
    //메시지전송
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws JsonMappingException, JsonProcessingException{
        try {
            String msg = message.getPayload();
            //fileUploadSession = msg;
            ObjectMapper objectMapper = new ObjectMapper();
            //ChattDTO dto =  objectMapper.readValue(msg, new TypeReference&lt;Map&lt;String, Object&gt;&gt;(){});
            Map&lt;String, Object&gt; chatMap =  objectMapper.readValue(msg, new TypeReference&lt;Map&lt;String, Object&gt;&gt;(){});
            String type=(String)chatMap.get(&quot;type&quot;);
            System.out.println(&quot;type:&quot;+type);
            if(!type.equals(&quot;fileUpload&quot;)) {
                for(String key : sessionMap.keySet()) {
                    WebSocketSession wss = sessionMap.get(key);
                    System.out.println(msg);

                    wss.sendMessage(new TextMessage(msg));

                }
            }else {
                fileUploadSession = msg;
                System.out.println(&quot;파일업로드가 발생됨&quot;+fileUploadSession);
//                for(String key : sessionMap.keySet()) {
//                    WebSocketSession wss = sessionMap.get(key);
//                    System.out.println(msg);
//                    
//                    wss.sendMessage(new TextMessage(msg));
//                    
//                }
            }
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {
        // TODO Auto-generated method stub
        //super.handleBinaryMessage(session, message);
        System.out.println(&quot;바이너리데이터 전송됨&quot;);
        System.out.println(message);

        ByteBuffer byteBuffer = message.getPayload();
        String fileName = &quot;temp.jpg&quot;;
        File dir = new File(FILE_UPLOAD_PATH);
        if(!dir.exists()) {
            dir.mkdirs();
        }

        File file = new File(FILE_UPLOAD_PATH, fileName);
        FileOutputStream out = null;
        FileChannel outChannel = null;
        try {
            byteBuffer.flip(); //byteBuffer를 읽기 위해 세팅
            out = new FileOutputStream(file, true); //생성을 위해 OutputStream을 연다.
            outChannel = out.getChannel(); //채널을 열고
            byteBuffer.compact(); //파일을 복사한다.
            outChannel.write(byteBuffer); //파일을 쓴다.
        }catch(Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(out != null) {
                    out.close();
                }
                if(outChannel != null) {
                    outChannel.close();
                }
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
        byteBuffer.position(0); //파일을 저장하면서 position값이 변경되었으므로 0으로 초기화한다.
        //파일쓰기가 끝나면 이미지를 발송한다.
        //HashMap&lt;String, Object&gt; temp = sessionMap.get(fileUploadIdx);
        for(String k : sessionMap.keySet()) {
//            
//            WebSocketSession wss = (WebSocketSession) temp.get(k);
            try {
                WebSocketSession wss = sessionMap.get(k);
                //System.out.println(msg);
                System.out.println(fileUploadSession+&quot;_______&quot;);
                wss.sendMessage(new TextMessage(fileUploadSession));

                wss.sendMessage(new BinaryMessage(byteBuffer)); //초기화된 버퍼를 발송한다.
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //소켓종료
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // TODO Auto-generated method stub
        System.out.println(&quot;종료&quot;);
        sessionMap.remove(session.getId());
        super.afterConnectionClosed(session, status);
    }

}</code></pre>
<h3 id="websocketconfigver2">WebSocketConfigVer2</h3>
<pre><code class="language-java">@Configuration
@EnableWebSocket
public class WebSocketConfigVer2 implements WebSocketConfigurer{

    //웹소켓 핸들러 객체에 매핑하기
    // /mywebsocket으로 요청하면 웹소켓핸들러가 동작할 수 있도록 등록하기
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myHendler(),&quot;/chatting&quot;);
        //.setAllowedOrigins(&quot;*&quot;);
        System.out.println(&quot;등록완료&quot;);
    }
    //핸들러 객체 리턴하기
    @Bean
    public WebSocketHandler myHendler() {
        return new MyBinaryHandler();
    }

    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
        container.setMaxTextMessageBufferSize(8192);
        container.setMaxBinaryMessageBufferSize(50000000);
        return container;
    }

}
</code></pre>
<h3 id="chatt2html">chatt2.html</h3>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;script
    src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js&quot;&gt;&lt;/script&gt;
    &lt;style type=&quot;text/css&quot;&gt;
        #talklist{
            border:1px solid;
            width: 600px;
            height: 400px;
            overflow: auto;
        }
        #msg{
            border:1px solid;
            width: 550px;
            margin-top: 10px
        }
        #sendbtn{
            height: 40px;
            margin-top: 10px;
        }
        #id{
            width: 350px;
            margin-bottom: 10px
        }
        .me{
            background: #F5F0C5;
            width: 70%;
            float: right;
            margin: 1px;
        }
        .other{
            background: #dcdcdc;
            width: 70%;
            float: left;
            margin: 1px
        }
    &lt;/style&gt;

&lt;/head&gt;
&lt;body&gt;
    &lt;div id=&#39;chatt&#39;&gt;
        &lt;h1&gt;웹 소켓 채팅~~&lt;/h1&gt;
        &lt;input type=&#39;text&#39; id=&#39;id&#39; &gt;
        &lt;input type=&#39;button&#39; value=&#39;채팅참여&#39; id=&#39;joinbtn&#39; &gt;
        &lt;input type=&#39;button&#39; value=&#39;채팅종료&#39; id=&#39;btnclose&#39; &gt;
        &lt;br/&gt;
        &lt;div id=&#39;talklist&#39;&gt;&lt;/div&gt;
        &lt;div id=&#39;sendZone&#39;&gt;
            &lt;textarea id=&#39;msg&#39; &gt;&lt;/textarea&gt;
            &lt;input type=&quot;file&quot; id=&quot;myimg&quot;&gt;
            &lt;input type=&#39;button&#39; value=&#39;전송&#39; id=&#39;sendbtn&#39;&gt;
            &lt;input type=&#39;button&#39; value=&#39;파일올리기&#39; id=&#39;filesend&#39; onclick=&quot;fileSend()&quot;&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;

        let mydata = {};//전송 데이터(JSON)
        $(document).ready(function(){
            $(&quot;#joinbtn&quot;).on(&quot;click&quot;, function(){
            //    ws = new WebSocket(&quot;ws://10.10.0.17/chatting&quot;);
            ws = new WebSocket(&quot;ws://&quot; + location.host + &quot;/chatting&quot;);
                //웹 소켓에서 메시지가 날라왔을 때 호출되는 이벤트
                let resid=&quot;&quot;;
                ws.onmessage = function(msg){
                    var data = msg.data;

                    if(data != null &amp;&amp; data.type != &#39;&#39;){
                        let resMsg = JSON.parse(data);
                        console.log(&quot;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&quot;+resMsg)
                        resid = resMsg.id
                        let msgcss = &quot;&quot;;
                        console.log(&quot;$$$$$$$$$$&quot;+resid)
                        if(resMsg.id == $(&quot;#id&quot;).val()){
                            msgcss = &#39;class=me&#39;;
                        }else{
                            msgcss = &#39;class=other&#39;;
                        }
                        //alert(msg.data)
                        let item = &quot;&lt;div &quot;+msgcss+&quot;&gt;&lt;span&gt;&lt;b&gt;&quot;+resMsg.id+&quot;&lt;/b&gt;&lt;/span&gt; [ &quot;+resMsg.date+&quot; ]&lt;br/&gt;&quot;+
                                    &quot;&lt;span&gt;&quot;+resMsg.msg+&quot;&lt;/span&gt;&lt;/div&gt;&quot;;
                        $(&quot;#talklist&quot;).append(item)

                        console.log(&quot;=====&quot;+resid);
                    }else{
                        console.log(&quot;--------&quot;+resid);
                        if(resid == $(&quot;#id&quot;).val()){
                            msgcss = &#39;class=me&#39;;
                        }else{
                            msgcss = &#39;class=other&#39;;
                        }
                        var url = URL.createObjectURL(new Blob([data]));
                        console.log(&quot;++++++++&quot;+msgcss)
                        let item = &quot;&lt;div &quot;+msgcss+&quot;&gt;&lt;span&gt;&lt;img class=&#39;msgImg&#39; src=&quot;+url+&quot; width=&#39;100&#39; height=&#39;100&#39;&gt;&lt;/span&gt;&lt;/div&gt;&quot;;
                        $(&quot;#talklist&quot;).append(item);
                    }
                    //alert($(&quot;#talklist&quot;).scrollHeight)
                //    console.log($(&quot;#talklist&quot;).height())
                    //console.log($(&quot;#talklist&quot;).s)
                    //$(&quot;#talklist&quot;).scrollTop(300)
                    $(&quot;#talklist&quot;).scrollIntoView(false)
                }
                 //웹 소켓이 연결되었을 때 호출되는 이벤트
                ws.onopen = function(message){
                    $(&quot;#talklist&quot;).append(&quot;server start...&quot;);
                };
                //웹 소켓이 닫혔을 때 호출되는 이벤트
                ws.onclose = function(message){
                    $(&quot;#talklist&quot;).append(&quot;Server Disconnect...\n&quot;);
                };
                //웹 소켓이 에러가 났을 때 호출되는 이벤트
                ws.onerror = function(message){

                    $(&quot;#talklist&quot;).append(message+&quot;error...\n&quot;);
                };

            })
            $(&quot;#msg&quot;).on(&quot;keyup&quot;,function(ev){
                if(ev.keyCode == 13){
                    sendMessage();
                }

            })
            $(&quot;#sendbtn&quot;).on(&quot;click&quot;,function(){
                sendMessage();
            })
            $(&quot;#btnclose&quot;).on(&quot;click&quot;,function(){
                ws.close();
            })

        })
        //Send 버튼을 누르면 실행되는 함수
        function sendMessage(){
            mydata.type= &quot;message&quot;;
            let message = $(&quot;#msg&quot;).val();
            //서버로 보낼 데이터 만들기
            mydata.id = $(&quot;#id&quot;).val();
            mydata.msg = message;
            mydata.date = new Date().toLocaleString();
            let sendmsg = JSON.stringify(mydata);
            //웹소켓으로 textMessage객체의 값을 보낸다.
            ws.send(sendmsg);
            $(&quot;#msg&quot;).val(&quot;&quot;);
        }
        function fileSend(){
            var file = document.querySelector(&quot;#myimg&quot;).files[0];
            var fileReader = new FileReader();
            fileReader.onload = function() {
                mydata.type= &quot;fileUpload&quot;,
                mydata.file= file;
                mydata.id = $(&quot;#id&quot;).val();
                mydata.msg = &quot;&quot;;
                mydata.date = new Date().toLocaleString();
                let sendmsg = JSON.stringify(mydata);

                ws.send(sendmsg); //파일 보내기전 메시지를 보내서 파일을 보냄을 명시한다.

                arrayBuffer = this.result;
                console.log(arrayBuffer);
                ws.send(arrayBuffer); //파일 소켓 전송
            };
            fileReader.readAsArrayBuffer(file);
        }
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 id="사진전송-결과보기">사진전송 결과보기</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/40269f33-1501-40da-b1fc-784f2ee3516a/image.png" alt=""></p>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹소켓. 채팅]]></title>
            <link>https://velog.io/@brave_chicken/%EC%9B%B9%EC%86%8C%EC%BC%93.-%EC%B1%84%ED%8C%85</link>
            <guid>https://velog.io/@brave_chicken/%EC%9B%B9%EC%86%8C%EC%BC%93.-%EC%B1%84%ED%8C%85</guid>
            <pubDate>Mon, 24 Jun 2024 10:14:35 GMT</pubDate>
            <description><![CDATA[<h1 id="웹소켓통신">웹소켓통신</h1>
<ul>
<li>HTML5표준기술</li>
<li>HTTP환경에서 TCP를 통해서 접속해서 통신</li>
<li>TCP통신을 통해 접속하므로 최초접속시에 3way handshake발생</li>
<li>연결유지</li>
<li>이벤트발생되고 이 이벤트에 대해서 처리하는 코드를 적용(SSE도 동일)</li>
<li>양방향통신(클라이언트에서 요청을 보내지 않아도 서버에서 메시지를 보낼 수 있다)</li>
<li>클라이언트는 자바스크립트 코드를 이용해서 작업</li>
<li>웹소켓은 Socket Connection을 유지한 상태로 양방향통신을 하면서 실시간 데이터 전
  =&gt; 텍스트전송, 바이너리전송 모두 가능</li>
<li>stateful(연결이 유지)</li>
<li>클라이언트와 서버가 한 번 연결되면 같은 연결을 통해서 통신하므로 TCP커넥션 비용 절약</li>
</ul>
<h2 id="이전방식">[이전방식]</h2>
<ul>
<li>폴링 : 일정주기를 가지고 서버의 API를 호출(2초마다 한번씩 호출하기)</li>
<li>롱폴링 : 폴링과 비슷, 요청이 서버로 간 후 대기했다가 요청한 데이터가 업데이트되면 서버에서 응답을 보낸다.</li>
</ul>
<p>==&gt; 리소스도 낭비, 실시간데이터를 주고받는것도 힘들다(채팅,주식,게임,...)</p>
<h2 id="최근방식">[최근방식]</h2>
<ul>
<li>웹소켓</li>
<li>SSE - 서버에서 웹브라우저로 메시지를 보내는 방법</li>
</ul>
<h2 id="웹소켓">[웹소켓]</h2>
<h3 id="1-설정">1. 설정</h3>
<ul>
<li>웹소켓 통신을 할 수 있도록 객체를 빈으로 만들어서 등록</li>
<li>ServerEndpointExporter등록
(웹소켓을 사용하기 위해서 필요한 객체)</li>
</ul>
<h3 id="2-핸들러작성">2. 핸들러작성</h3>
<ul>
<li>컨트롤러처럼 웹소켓통신을 할 수 있도록 제공되는 객체</li>
<li>클라이언트가 접속하면 클라이언트와 연결, 통신할 수 있도록 제공되는 클래스
클라이언트와 서버가 연결해서 하고싶은 작업은 여기에 정의</li>
<li>웹소켓 서버의 역할을 하는 객체(웹소켓 통신할때 요청을 받는 역할)</li>
<li>endpoint(path)를 등록해야
어떻게 요청하면 서버와 요청할 수 있는지 path를 등록
클라이언트의 요청을 핸들러에서 받아야하는데 클라이언트에서 어떻게 요청하면 핸들러가 동작할지 path를 등록</li>
<li>이벤트 드리븐 방식
접속, 메시지전송, 오류, 접속종료 등 이벤트가 발생하면 반응하는 방식</li>
<li>웹소켓 내부에서도 세션을 관리할 수 있다.
HttpSession과 다른 세션
웹소켓 통신 내부에서 관리하는 세션
웹소켓 통신을 하는 클라이언트를 구분하기 위한 세션</li>
</ul>
<h3 id="3-자바스크립트로-클라이언트에서-통신할-코드를-작성">3. 자바스크립트로 클라이언트에서 통신할 코드를 작성</h3>
<h1 id="실습">실습</h1>
<h3 id="spring-initializr">spring initializr</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/4cfd7614-d10c-446e-acc7-fd5efd1260ca/image.png" alt=""></p>
<h3 id="디렉토리-구성">디렉토리 구성</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/3121e7ed-7766-4a2d-a4b7-648f59c84676/image.png" alt=""></p>
<h3 id="build-gradle">build gradle</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/b9f87bad-0808-445b-9ac6-6d18e266a990/image.png" alt=""></p>
<h3 id="applicationproperties">application.properties</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/2851d667-d73f-4eef-8bd8-e2c93e113c60/image.png" alt=""></p>
<h3 id="websocketconfig">WebSocketConfig</h3>
<p>웹소켓컨테이너를 활성화시키는 작업 - 웹소켓을 사용하겠다고 정의</p>
<pre><code class="language-java">@Configuration
@EnableWebSocket
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}</code></pre>
<h3 id="websocketcontroller">WebSocketController</h3>
<pre><code class="language-java">@Controller
public class WebSocketController {
    @GetMapping(&quot;/chat&quot;)
    public String showview(){
        return &quot;chat&quot;;
    }
}</code></pre>
<h3 id="websocketbasichandler">WebSocketBasicHandler</h3>
<p>웹소켓통신을 하면서 서버역할을 하는 프로그램</p>
<pre><code class="language-java">@Component
@ServerEndpoint(value = &quot;/chat&quot;)
public class WebSocketBasicHandler {
    //세션을 저장하기 위해서 컬렉션을 추가
    //동기화된 컬렉션 - 멀티스레드환경에서 안전하게 작업할 수 있도록 제공되는 set
    private static Set&lt;Session&gt; clientlist = Collections.synchronizedSet(new HashSet&lt;&gt;());

    //클라이언트가 접속을하면 실행되는 메소드
    @OnOpen
    public void open(Session client){
        System.out.println(&quot;클라이언트가 접속했다&quot;);
        System.out.println(client);
        if (!clientlist.contains(client)){
            clientlist.add(client);
        }
    }
    //클라이언트에게 메시지를 받으면 호출되는 메소드
    //통신할때 메시지를 받으면 호출되는 메소드로 모든 접속자들한테 메시지를 전송할 수 있어야 한다.
    //메시지를 받을때마다 호출되는 메소드
    //텍스트메시지통신(웹소켓에 접속한 모든 클라이언트에게 메시지를 전송)
    @OnMessage
    public void onMessage(String msg,Session sender) throws IOException {
       //웹소켓에 접속한 모든 클라이언트에게 메시지전송
        System.out.println(&quot;수신된 메시지:&quot;+msg);
        System.out.println(&quot;클라이언트:&quot;+sender);
        for(Session client:clientlist){
            client.getBasicRemote().sendText(msg);
        }
    }
    @OnClose
    //접속종료 - 소켓연결이 끊어지면 호출되는 메소드
    public void onClose(Session client){
        System.out.println(&quot;접속종료&quot;);
        clientlist.remove(client);
    }
}</code></pre>
<h3 id="chathtml">chat.html</h3>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
  &lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js&quot;&gt;&lt;/script&gt;
    &lt;style type=&quot;text/css&quot;&gt;
        #talklist{
            border:1px solid;
            width: 600px;
            height: 400px
        }
        #msg{
            border:1px solid;
            width: 550px;
            margin-top: 10px
        }
        #sendbtn{
            height: 40px;
            margin-top: 10px;
        }
        #id{
            width: 350px;
            margin-bottom: 10px
        }
        .me{
            background-color: #FAECC5;
            width: 70%;
            float: right;
            margin: 1px
        }
        .other{
            background-color: #EAEAEA;
            width: 70%;
            float: left;
            margin: 1px
        }
    &lt;/style&gt;

&lt;/head&gt;
&lt;body&gt;
    &lt;div id=&#39;chatt&#39;&gt;
        &lt;h1&gt;웹 소켓 채팅&lt;/h1&gt;
        &lt;input type=&#39;text&#39; id=&#39;id&#39; &gt;
        &lt;input type=&#39;button&#39; value=&#39;채팅참여&#39; id=&#39;joinbtn&#39; &gt;
        &lt;input type=&#39;button&#39; value=&#39;채팅종료&#39; id=&#39;btnclose&#39; &gt;
        &lt;br/&gt;
        &lt;div id=&#39;talklist&#39;&gt;&lt;/div&gt;
        &lt;div id=&#39;sendZone&#39;&gt;
                &lt;textarea id=&#39;msg&#39; &gt;&lt;/textarea&gt;
            &lt;input type=&#39;button&#39; value=&#39;전송&#39; id=&#39;sendbtn&#39;&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
        //전송할 데이터가 여러개이므로 json으로 전송
        let mydata = {};

        $(document).ready(function(){
            $(&quot;#joinbtn&quot;).on(&quot;click&quot;,function(){
                //alert(location.host);
                //1. 웹소켓객체를 생성 - 서버에 연결하는 작업
                ws = new WebSocket(&quot;ws://&quot;+location.host+&quot;/chat&quot;);
                //연결이 되면 이벤트에 반응할 수 있도록 콜백등록

                //웹소켓에서 클라이언트로 전송하는 메시지를 받을 수 있도록 처리
                //웹소켓에 연결된 후에 실행
                ws.onopen = function(msg){
                    console.log(msg);
                    $(&quot;#talklist&quot;).append(&quot;&lt;div&gt;접속완료....&lt;/div&gt;&quot;);
                }
                //웹소켓 연결 후에 서버가 메시지를 보내면 받을 수 있도록 콜백등록
                ws.onmessage = function(msg){
                    //실제 데이터가 json으로 전송
                    console.log(msg.data);
                    //받은 메시지를 출력 - 내가 보낸건지 받은 메시지인지 확인하기 위해서 id하고 비교
                    //전송되는 메시지에서 데이터만 추출
                    //json데이터에 저장된 값을 엑세스하려면 JSON문자열을 parsing해야한다.
                    let resMsg = JSON.parse(msg.data);
                    console.log(resMsg);
                    let msgcss = &quot;&quot;;
                    if(resMsg.id==$(&quot;#id&quot;).val()){//내가 작성한 메시지인지 확인
                        msgcss = &quot;class = me&quot;;
                    }else{
                        msgcss = &quot;class = other&quot;;
                    }
                    //talklist에 출력할 div생성
                    let item = &quot;&lt;div &quot;+ msgcss+ &quot; &gt;&lt;span&gt;&lt;b&gt;&quot;+ resMsg.id+ &quot;&lt;/b&gt;&lt;/span&gt;&quot;
                               + &quot;&lt;b&gt;[&quot;+ resMsg.date+ &quot;]&lt;/b&gt;&lt;br/&gt;&quot;
                               + &quot;&lt;span&gt;&quot;+ resMsg.msg +&quot;&lt;/span&gt;&quot;
                               +&quot;&lt;/div&gt;&quot;
                    $(&quot;#talklist&quot;).append(item);
                }
                //웹소켓이 종료된 후에 발생하는 이벤트에 대해서 처리할 수 있도록 콜백등록
                ws.onclose = function(msg){
                    //실제 데이터가 json으로 전송
                    console.log(msg);
                    $(&quot;#talklist&quot;).append(&quot;&lt;div&gt;접속종료....&lt;/div&gt;&quot;);
                }
                ws.onerror = function(msg){
                    //실제 데이터가 json으로 전송
                    console.log(msg);
                    $(&quot;#talklist&quot;).append(&quot;&lt;div&gt;에러발생....&lt;/div&gt;&quot;);
                }
            });
            $(&quot;#sendbtn&quot;).on(&quot;click&quot;,function(){
                sendMessage();
            })
            $(&quot;#msg&quot;).on(&quot;click&quot;,function(event){
                //엔터키가 눌려지면
                if(event.keyCode==13){
                    sendMessage();
                }
            })
            $(&quot;#btnclose&quot;).on(&quot;click&quot;,function(){
                //웹소켓연결종료
                ws.close();
            })
        })
        function sendMessage(){
            //메시지전송함수
            //서버로 보낼 메시지를 만들어서 전송
            //지금은 id를 &lt;input&gt;에서 꺼내지만 나중에는 웹의 세션에 저장된 dto에서 꺼내기
            mydata.id = $(&quot;#id&quot;).val();
            mydata.msg = $(&quot;#msg&quot;).val();
            mydata.date = new Date().toLocaleDateString();//오늘날짜
            mydata.type = &quot;textmsg&quot;;//메시지유형(텍스트와 바이너리를 구분하기 위한 값)

            //자바스크립트 객체로 정의된 데이터를 json문자열로 변환
            let sendMsg = JSON.stringify(mydata);
            ws.send(sendMsg);//웹소켓서버로 메시지를 전송
            $(&quot;#msg&quot;).val(&quot;&quot;);//메시지전송이 완료되면 텍스트창을 지우기
        }
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 id="결과">결과</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/c874ed2f-cab6-489c-8dd6-dae5ebde0e67/image.png" alt=""></p>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네이버클라우드 서버연결/배포]]></title>
            <link>https://velog.io/@brave_chicken/240624</link>
            <guid>https://velog.io/@brave_chicken/240624</guid>
            <pubDate>Mon, 24 Jun 2024 09:52:16 GMT</pubDate>
            <description><![CDATA[<h3 id="디비버에서-데이터베이스연결mysql">디비버에서 데이터베이스연결(mysql)</h3>
<p>(강사님이 만드신거)
<img src="https://velog.velcdn.com/images/brave_chicken/post/83ccb784-fa0f-420b-8697-aedd203a59fd/image.png" alt=""></p>
<h3 id="application-properties에서-url-connectiontest에서-urlsql문-변경">application properties에서 url, ConnectionTest에서 url,sql문 변경</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/5d829abe-e2eb-4310-849c-4c048bc91859/image.png" alt=""></p>
<h3 id="putty-접속">putty 접속</h3>
<p>putty에서 공인ip로 연결해서 패스워드 적어둔거 우클해서 접속</p>
<h3 id="명령어정리">명령어정리</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/4fb4b8e8-eea2-498b-a89e-050e2d6995f2/image.png" alt=""></p>
<h4 id="rootmyserver3-1">root@myserver3-1:~#</h4>
<ul>
<li><p>~ : 홈디렉토리</p>
</li>
<li><p>/ : 최상위디렉토리로 이동(루트디렉토리)</p>
</li>
<li><p>#: 관리자계정</p>
</li>
<li><p>$ : 일반 사용자 계정</p>
</li>
</ul>
<h4 id="리눅스폴더">리눅스폴더</h4>
<ul>
<li><p>/home : 각 사용자들의 홈디렉토리가 만들어지는 위치</p>
</li>
<li><p>** 홈디렉토리 : 특정 사용자 계정으로 로그인했을때 자동으로 위치하는 디렉토리, 모든 사용자는 자신만의 홈디렉토리를 갖는다.</p>
</li>
<li><p>/boot : 부팅에 필요한 설정파일이 위치하는 폴더</p>
</li>
<li><p>/bin : shell명령어가 위치한 폴더</p>
</li>
<li><p>/etc : 시스템관리를 위해서 필요한 각종 설정 파일이 위치하는 곳
네트워크, 사용자, 파일시스템, 설치한 각종 프로그램의 설정파일...</p>
</li>
<li><p>/usr : 윈도우의 programfiles와 유사</p>
</li>
</ul>
<h4 id="리눅스명령어">리눅스명령어</h4>
<ul>
<li><p>pwd : 현재 위치확인</p>
</li>
<li><p>cd : 폴더이동
cd ~ : root로 이동</p>
</li>
<li><p>ls : 도스명령어의 dir과 동일, 폴더 안에 어떤 내용이 들어있는지 보기 위해서 사용</p>
</li>
<li><p>mkdir : 디렉토리 만들기
mkdir 디렉토리명</p>
</li>
<li><p>touch : 빈파일 만들기
touch 파일명</p>
</li>
<li><p>cp : 파일복사</p>
</li>
<li><p><em>디렉토리에서 다른 디렉토리로 복사*</em>하는 경우
cp 파일명 복사할위치</p>
</li>
<li><p><em>디렉토리를 복사*</em>
cp 복사할디렉토리경로 대상디렉토리
cp ./test(소스디렉토리) test2(타겟디렉토리)</p>
</li>
<li><p>scp : 복사(내머신-&gt; 다른머신으로 복사)
호스트에서 다른 호스트로 복사하는 경우(윈10버전부터 사용할 수 있도록 지원)</p>
</li>
<li><p>rm : 파일삭제
rm 삭제할파일</p>
</li>
<li><p>rm : 폴더삭제
rm -r 폴더명</p>
</li>
<li><p>scp
호스트 -&gt; 호스트로 카피(디렉토리, 파일)
scp 복사할파일명(위치포함)(나의호스트) 대상위치(위치포함)(상대방호스트 : 계정@ip:/경로)
scp ./ljh <a href="mailto:root@223.130.157.214">root@223.130.157.214</a>:/root/exam</p>
</li>
</ul>
<h3 id="미션">[미션]</h3>
<ul>
<li>myfile1, myfile2, myfile3 파일을 3개 생성하기</li>
<li>mytest폴더생성</li>
<li>mytest폴더로 3개의 파일을 복사</li>
<li>mytest폴더에 sub폴더 생성</li>
<li>mytest폴더의 내용을 확인</li>
</ul>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/49acf579-5d8c-4944-bd73-29a4aa3b4162/image.png" alt=""></p>
<h3 id="파일-만들어서-다른-ip로-보내기">파일 만들어서 다른 ip로 보내기</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/84e8f83c-ca25-4513-83b3-017d85b9e3da/image.png" alt=""></p>
<h2 id="배포하기">[배포하기]</h2>
<h3 id="1-jar파일로-패키징">1. jar파일로 패키징</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/5ca4f57b-045d-4cb7-b85f-72a91927d278/image.png" alt=""></p>
<h3 id="2-scp명령어를-이용해서-서버로-복사">2. scp명령어를 이용해서 서버로 복사</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/2cb7762d-6b71-4c34-949d-16469384510f/image.png" alt=""></p>
<h3 id="3-실행">3. 실행</h3>
<ul>
<li>os내부의 패키지(소프트웨어) 업데이트
sudo apt update
<img src="https://velog.velcdn.com/images/brave_chicken/post/68e47cd6-dfcb-4df6-b0d8-af62f35d39e0/image.png" alt=""></li>
</ul>
<ul>
<li>java설치
sudo apt install openjdk-17-jdk</li>
</ul>
<ul>
<li>실행
java -jar erp-0.0.1-SNAPSHOT.jar</li>
</ul>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/64e204c7-dab7-4750-bf5e-c546a827de9d/image.png" alt=""></p>
<h3 id="localhost자리에-해당-ip넣기">localhost자리에 해당 ip넣기</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/a7f446cf-e1fc-4593-9c59-9ac6fc7ae737/image.png" alt=""></p>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네이버클라우드 서버배포]]></title>
            <link>https://velog.io/@brave_chicken/240621</link>
            <guid>https://velog.io/@brave_chicken/240621</guid>
            <pubDate>Mon, 24 Jun 2024 00:11:32 GMT</pubDate>
            <description><![CDATA[<h3 id="서버배포-학습단계">서버배포 학습단계</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/6707f5ee-b7a0-445e-8557-73a20f3ac269/image.png" alt="">
<a href="https://m.blog.naver.com/heaves1/223424605755">https://m.blog.naver.com/heaves1/223424605755</a>
참고사이트 링크</p>
<h3 id="vpc생성">VPC생성</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/c6e6994c-04af-4c33-96cf-7e6613302434/image.png" alt=""></p>
<h3 id="network-acl생성">Network ACL생성</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/c5ed3e33-1e42-4b57-8039-f1cf64285e9d/image.png" alt=""></p>
<h3 id="network-acl-규칙설정">Network ACL 규칙설정</h3>
<p>인바운드 포트는 팀프로젝트 포트
<img src="https://velog.velcdn.com/images/brave_chicken/post/eb49780e-b459-48a9-87c6-68cdda727f24/image.png" alt="">
아웃바운드포트는 아무나 다 가능하게하는(?) 1-65535
<img src="https://velog.velcdn.com/images/brave_chicken/post/cbc7c27b-01d4-42af-b4be-cda136eddf34/image.png" alt=""></p>
<h3 id="서브넷-생성">서브넷 생성</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/1c625cb9-e402-4601-ab37-a28eb0721637/image.png" alt=""></p>
<h3 id="acg-생성">ACG 생성</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/1005f2c1-e500-435a-a2ac-63426b376001/image.png" alt=""></p>
<h3 id="acg-규칙설정">ACG 규칙설정</h3>
<p>인바운드
<img src="https://velog.velcdn.com/images/brave_chicken/post/0d249020-a3e5-4a4e-b148-61539d533266/image.png" alt="">
아웃바운드
<img src="https://velog.velcdn.com/images/brave_chicken/post/6f1d010c-3391-4b5c-82c5-26c48a052aa2/image.png" alt=""></p>
<h3 id="서버생성">서버생성</h3>
<p>1,2단계는 다시.. 지금은 연습이라 다르게했음
인증키 설정
<img src="https://velog.velcdn.com/images/brave_chicken/post/0552ab56-b271-4d67-89c0-13150b1d2972/image.png" alt="">
네트워크 접근설정
<img src="https://velog.velcdn.com/images/brave_chicken/post/b3b3e3c2-d3a7-4a0f-8c04-76a6b10dd961/image.png" alt="">
선택한거 확인
<img src="https://velog.velcdn.com/images/brave_chicken/post/188add08-d839-4b73-aade-990779d181b8/image.png" alt=""></p>
<h3 id="공인ip신청">공인IP신청</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/8ee0cf17-03c4-461b-bb1f-7b132eea1f07/image.png" alt=""></p>
<p>확인
<img src="https://velog.velcdn.com/images/brave_chicken/post/01491992-8346-4fb7-9fef-ecf44b9ab4a2/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/f7a5792e-1f87-40d3-ab13-e0b88fb988ce/image.png" alt=""></p>
<h3 id="db">DB</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/6eb5e306-65ad-46bb-aa58-a9f8fa0f2699/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/18558516-507c-45e8-90dc-e681c5e5a182/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/cb9a8091-e323-4711-a7de-dca0157feba8/image.png" alt=""></p>
<h3 id="acg">acg</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/b3da2a66-227d-42d8-b37a-742d24c39818/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/c5e04ca3-2f07-4b4b-955e-fa8d452e5ffc/image.png" alt=""></p>
<h3 id="intellij-erp와-연결해보기">intelliJ erp와 연결해보기</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/f517ab31-414f-4a86-bd5a-2a392bc6012c/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/d4601cb5-8e31-46bd-90d6-7b62a05aaf9a/image.png" alt=""></p>
<h3 id="connectiontest">ConnectionTest</h3>
<pre><code class="language-java">public class ConnectionTest {
    public static void main(String[] args) {
        String url=&quot;jdbc:mysql://db-nttta-kr.vpc-pub-cdb.ntruss.com:3306/test?serverTimezone=UTC&quot;;
        String user=&quot;myerp&quot;;
        String password=&quot;myerp2024!&quot;;
        try {
            //1. 드라이버로딩
            Class.forName(&quot;com.mysql.cj.jdbc.Driver&quot;);
            System.out.println(&quot;드라이버로딩성공!!&quot;);
            //2. 연결
            Connection con = DriverManager.getConnection(url, user, password);
            PreparedStatement ptmt =  con.prepareStatement(&quot;select * from TBBOARD&quot;);
            ResultSet rs =  ptmt.executeQuery();
            while (rs.next()){
                System.out.println(rs.getString(1));
            }
            System.out.println(&quot;연결성공!!&quot;+con);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }
}</code></pre>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[spring security crypto 이용- 암호화된 로그인]]></title>
            <link>https://velog.io/@brave_chicken/spring-security-crypto-%EC%9D%B4%EC%9A%A9-%EC%95%94%ED%98%B8%ED%99%94%EB%90%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8</link>
            <guid>https://velog.io/@brave_chicken/spring-security-crypto-%EC%9D%B4%EC%9A%A9-%EC%95%94%ED%98%B8%ED%99%94%EB%90%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8</guid>
            <pubDate>Thu, 20 Jun 2024 02:11:17 GMT</pubDate>
            <description><![CDATA[<h3 id="buildgradle에-아래코드-추가--리빌드">build.gradle에 아래코드 추가 &amp; 리빌드</h3>
<pre><code>implementation &#39;org.springframework.security:spring-security-crypto:5.7.1&#39;</code></pre><h3 id="passwordconfig-생성">PasswordConfig 생성</h3>
<pre><code class="language-java">@Configuration
public class PasswordConfig {
    //PasswordEncoder : 패스워드 암호화를 위해 제공되는 상위클래스
    //PasswordEncoder객체를 만들어서 제공
    @Bean
    public PasswordEncoder passwordEncoder(){
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}</code></pre>
<h3 id="register-변경---인원등록부분">register 변경 - 인원등록부분</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/69a6d101-a893-4a6f-b2cc-0b9fec522605/image.png" alt=""></p>
<h3 id="membercontroller">MemberController</h3>
<h4 id="편의상-변경된-사항만-기입">편의상 변경된 사항만 기입</h4>
<pre><code class="language-java">@Controller
@RequestMapping(&quot;/member&quot;)
@SessionAttributes(&quot;user&quot;)
@RequiredArgsConstructor
public class MemberController {
    private final MemberService service;
    private final DeptService deptservice;
    private final FileUploadService fileuploadService;
    private final PasswordEncoder passwordEncoder;


//    스프링에서 제공되는 기능을 이용해서 로그인 처리하기
    @PostMapping(&quot;/spring/login&quot;)
    public String springlogin(MemberDTO loginUserInfo, Model model) {
        System.out.println(&quot;스프링이 제공하는 @SessionAttributes를 이용해서 로그인&quot;);
        MemberDTO user = service.login(loginUserInfo);
        System.out.println(&quot;------------로그인한 사용자정보:&quot;+user);
        String view = &quot;&quot;;

        /*
        passwordEncoder.matches(loginUserInfo.getPass(), user.getPass())
                                ----------------------    ---------------
                                로그인하며 사용자가 입력한 값     디비에서 조회한 사용자의 패스워드값
        =&gt; 로그인하며 사용자가 입력한 값을 암호화하고 디비에 저장된 값을 비교해서 일치하면 true 아니면 false
        */
        if(user!=null &amp; passwordEncoder.matches(loginUserInfo.getPass(), user.getPass())) {
            System.out.println(&quot;패스워드 일치&quot;);
            model.addAttribute(&quot;user&quot;,user);
            view = &quot;emp/mypage&quot;;//타임리프쓰니 서브메뉴로 로그인했을때 각 부서 정의해놓음
        }else {
            System.out.println(&quot;패스워드 불일치&quot;);
            view = &quot;redirect:/emp/login.do&quot;;
        }

        /*
        암호화하기 전의 로그인
        if(user!=null) {
            //로그인성공
            model.addAttribute(&quot;user&quot;,user);
            view = &quot;emp/mypage&quot;;//타임리프쓰니 서브메뉴로 로그인했을때 각 부서 정의해놓음
        }else {
            //로그인실패
            view = &quot;redirect:/emp/login.do&quot;;
        }*/

        return view;
    }


    @GetMapping(&quot;/insert&quot;)
    public String insert(Model model) {
        //기존의 DeptServiceImpl의 셀렉트메소드를 호출해서 결과를 공유
        List&lt;DeptDTO&gt; deptlist = deptservice.select();
        model.addAttribute(&quot;deptlist&quot;,deptlist);
        return &quot;emp/register&quot;;
    }
    @PostMapping(&quot;/insert&quot;)
    public String insertPage(MemberDTO member, HttpSession session) 
                                        throws IllegalStateException, IOException{
        //패스워드 암호화
        String encodedPass = passwordEncoder.encode(member.getPass());
        System.out.println(&quot;-----------&quot;+encodedPass);

        //암호화된 패스워드 세팅
        member.setPass(encodedPass);


        System.out.println(member);
        //1. 파일업로드
        MultipartFile file = member.getUserImage();
        String path = WebUtils.getRealPath(session.getServletContext(), &quot;/WEB-INF/upload&quot;);
        String storeFilename = fileuploadService.uploadFile(file);
        member.setProfile_photo(storeFilename);
        member.setGender(&quot;0&quot;);
        System.out.println(member);
        //2.디비에 저장하기
        service.insert(member);

        return &quot;emp/register&quot;;
    }

}</code></pre>
<h3 id="member-매퍼-변경">member 매퍼 변경</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/aa9dee1f-b8ba-4f86-a1db-3fcdf71c3d21/image.png" alt=""></p>
<h3 id="db수정">DB수정</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/8a7edef9-4cd1-40b1-ba3b-a5d76ec92020/image.png" alt="">
암호화된 패스워드가 등록되니 패스워드 길이 변경</p>
<h3 id="입력결과">입력결과</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/5e9c158b-a875-4e3b-b362-b86829724c1a/image.png" alt="">
password자리에 암호화된 키 삽입됨</p>
<h3 id="수업현황-및-기타">수업현황 및 기타</h3>
<ul>
<li>팀프로젝트 진행으로 필요한 부분만 추출해서 수업해주심</li>
<li>spring security + redis(메모리 db) + kafka(비동기통신) 과정 끝나고 공부할 것 권장 =&gt; (프론트독립, 스케일아웃, MSA(서비스단위분리)로 보안처리 강화에 필요)</li>
<li>암호화한 것은 복호화할 수 없음</li>
<li>토큰과 세션..</li>
<li>로그인정책<ul>
<li>사용자가 입력한 아이디 이용하여 사용자 조회</li>
<li>사용자가 입력한 패스워드를 암호화하여 맵에 지정된 패스워드와 일치하는지 조회</li>
</ul>
</li>
</ul>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JPA]]></title>
            <link>https://velog.io/@brave_chicken/JPA-38j0duvc</link>
            <guid>https://velog.io/@brave_chicken/JPA-38j0duvc</guid>
            <pubDate>Wed, 19 Jun 2024 04:33:53 GMT</pubDate>
            <description><![CDATA[<h3 id="categoryapicontroller">CategoryAPIController</h3>
<pre><code class="language-java">//api패키지의 모든 컨트롤러는 RestController
//JSON을 리턴하는 메소드
@RestController
@RequiredArgsConstructor
@RequestMapping(&quot;/api&quot;)
//로그기록
@Slf4j
public class CategoryAPIController {
    private final CategoryService categoryService;
    //카테고리를 추가하기 위한 데이터를 JSON으로 입력받고 싶은 경우
    //JSON으로 입력데이터를 만들어서 요청하면 스프링이 DTO로 변환
    //작업이 완료되면 성공완료됐는지만 넘기기
    //@RequestBody ---&gt; json데이터 -&gt; DTO로 변환해서 매개변수에 전달
    //@RequestBody ---&gt; 자바객체 -&gt; json데이터로 변환해서 응답
    @PostMapping(&quot;/category/insert&quot;)
    public ResponseEntity&lt;?&gt; insert(@RequestBody CategoryRequestDTO inputdata){
        System.out.println(inputdata);
        categoryService.write(inputdata);
        //ResponseEntity는 상태코드와 응답데이터의 본문을 설정
        //성공응답을 200 응답을 생성하고 별도의 본문없이 응답을 반환 - ok메시지
       // return ResponseEntity.ok().build(); -&gt;원래 이렇게하면됨 밑은 ok사인 찍고싶어서하는것
        return ResponseEntity.ok(HttpStatus.OK);
    }
    @GetMapping(&quot;/category/{categoryId}&quot;)
    public CategoryResponseDTO read(@PathVariable(&quot;categoryId&quot;) String catrgoryId){
        return categoryService.findById(Long.parseLong(catrgoryId));
    }

    //뷰가 없어서 처리결과를 JSON으로 만들어서 리턴 - Ajax요청결과
    //뷰로 response하는 경우는 String(뷰) 리턴하고 결과를 Model에 add시킨다.
    @GetMapping(&quot;/category/list&quot;)
    public List&lt;CategoryResponseDTO&gt; list(){
        return categoryService.findAll();
    }

    @GetMapping(&quot;/category/pagelist&quot;)
    public List&lt;CategoryResponseDTO&gt; pagelist(){
        return categoryService.pagingFindAll();
    }
}</code></pre>
<h3 id="categoryrepository">CategoryRepository</h3>
<pre><code class="language-java">//Repository인터페이스는 내부적으로 구현체를 스프링프레임워크에서 제공하므로 이 자체가 DAO의 역할을 할 수 있다.
//서비스단에서 Repository를 직접 호출해서 사용할 수 있다(프로젝트의 규모가 작은곳)
// view -&gt; controller -&gt; service -&gt; repository

//규모가 큰 프로젝트 같은 경우 view -&gt; controller -&gt; service -&gt; dao -&gt; repository순서로 호출
public interface CategoryRepository extends JpaRepository&lt;CategoryEntity,Long&gt; {
    //로그인 - 컬럼이 id와 pass라 가정(and조건)
    //CategoryEntity findByIdAndPass(String id, String pass);
    List&lt;CategoryEntity&gt; findByCategoryNameContaining(String categoryName);
    //categoryName컬럼이 매개변수로 시작하는 경우 조회
    List&lt;CategoryEntity&gt; findByCategoryNameStartingWith(String categoryName);
    //위의 메소드와 동일한데 페이징처리를 하고싶은 경우
    Page&lt;CategoryEntity&gt; findByCategoryNameStartingWith(String categoryName, Pageable pageRequest);
    Slice&lt;CategoryEntity&gt; findByInfoStartingWith(String info, Pageable pageRequest);
}</code></pre>
<h3 id="categorydaoimpl">CategoryDAOImpl</h3>
<pre><code class="language-java">@Repository
@RequiredArgsConstructor
public class CategoryDAOImpl implements CategoryDAO{
    //스프링프레임워크가 CategoryRepository의 구현체를 만들어서 autowired한다.
    private final CategoryRepository repository;

    @Override
    public void write(CategoryEntity category) {
        //create
        repository.save(category);
    }

    @Override
    public List&lt;CategoryEntity&gt; findAll() {
        //List
        return repository.findAll();
    }

    @Override
    public List&lt;CategoryEntity&gt; pagingFindAll() {
        //페이징처리
        //1. Pageable객체만들기
        //2. repository의 페이징메소드 호출
        //3. 리턴되는 Page객체에서 List에 저장된 Entity추출하기

        //셋팅해야하는 값들을 매개변수로 전달받아서 셋팅 - pageNumber
        PageRequest pageRequest = PageRequest.of(0, 5, Sort.by(Sort.Direction.DESC, &quot;categoryId&quot;));
        Page&lt;CategoryEntity&gt; page =repository.findAll(pageRequest);
        System.out.println(&quot;-----------------------&quot;);
        System.out.println(&quot;전체레코드수=&gt;&quot;+page.getTotalElements());
        System.out.println(&quot;페이지수=&gt;&quot;+page.getTotalPages());
        System.out.println(&quot;조회한 레코드수=&gt;&quot;+page.getNumberOfElements());
        System.out.println(&quot;한페이지사이즈=&gt;&quot;+page.getSize());
        System.out.println(&quot;-----------------------&quot;);
        return page.getContent();
    }

    @Override
    public CategoryEntity findById(long categoryId) {
        //read
        return repository.findById(categoryId).get();
    }
}</code></pre>
<h3 id="categoryserviceimpl">CategoryServiceImpl</h3>
<pre><code class="language-java">@Service
@RequiredArgsConstructor
public class CategoryServiceImpl implements CategoryService{
    private final CategoryDAO dao;
    @Override
    public void write(CategoryRequestDTO category) {
        //컨트롤러에서 넘겨받은 CategoryRequestDTO를 entity로 변환해서 넘기기
        //step01 - 생성자를 이용해서 직접 변경
        //CategoryEntity entity = new CategoryEntity(category.getCategoryName(),category.getInfo());
        ModelMapper mapper = new ModelMapper();
        //CategoryRequestDTO가 CategoryEntity로 자동변환
        CategoryEntity entity = mapper.map(category,CategoryEntity.class);
        dao.write(entity);
    }

    @Override
    public List&lt;CategoryResponseDTO&gt; findAll() {
        List&lt;CategoryEntity&gt; entityList = dao.findAll();
        //Entity를 뷰로 넘기면 안된다. entity를 DTO로 변환
        //step3 스트림으로 변환해서 작업
        //=&gt; 스트림은 자바8부터 도입된 API로 컬렉션의 요소를 하나씩 참조해서 여러가지 변환작업이 가능하거나 람다식을 반복처리할 수 있도록 편리한 기능을 제공
        //1. 스트림으로 변환
        //2. 데이터가공 -중간연산
        //map() -&gt; 스트림이 갖고있는 각 요소를 원하는 메소드나 생성자 등을 적용해서 변환할 수 있다.
        // 클래스명 :: 메소드명
        // 클래스명 :: new
        //=&gt; :: 연산자를 통해 new를 참조하는 경우에는 해당 생성자가 미리 만들어져 있다는 것을 전제
        //3. 변환된 요소를 새로운 리스트로 만드는 작업
        List&lt;CategoryResponseDTO&gt; categoryList = entityList.stream()
                                                .map(CategoryResponseDTO :: new)
                                                .collect(Collectors.toList());
        return categoryList;
    }

    @Override
    public List&lt;CategoryResponseDTO&gt; pagingFindAll() {
        //dao의 메소드를 호출하고 데이터를 변환
        List&lt;CategoryEntity&gt; entityList = dao.pagingFindAll();
        //step4. 스트림으로 변환(ModelMapper를 이용)
        ModelMapper mapper = new ModelMapper();
        List&lt;CategoryResponseDTO&gt; categorylist = entityList.stream()
                .map(entity -&gt; mapper.map(entity, CategoryResponseDTO.class))
                .collect(Collectors.toList());
        return categorylist;
    }

    @Override
    public CategoryResponseDTO findById(long categoryId) {
        //Entity를 DTO로 변환해서 넘기기
        //step2 builder를 활용해서 작업하기
        CategoryEntity entity = dao.findById(categoryId);

        return CategoryResponseDTO.builder()
                .categoryId(entity.getCategoryId())
                .categoryName(entity.getCategoryName())
                .info(entity.getInfo())
                .build();
    }
}</code></pre>
<h3 id="categorydaoimpltest">CategoryDAOImplTest</h3>
<pre><code class="language-java">@SpringBootTest
@Transactional
@Rollback(value = false)
class CategoryDAOImplTest {
    @Autowired
    CategoryRepository repository;

    @Test
    public void test1(){
        CategoryEntity category1 = new CategoryEntity(&quot;셔츠&quot;,&quot;블라우스포함&quot;);
        CategoryEntity category2 = new CategoryEntity(&quot;가방&quot;,&quot;자체제작&quot;);
        CategoryEntity category3 = new CategoryEntity(&quot;팬츠&quot;,&quot;반바지포함&quot;);
        CategoryEntity category4 = new CategoryEntity(&quot;악세사리&quot;,&quot;목걸이, 리본포함&quot;);
        //한꺼번에 insert
        repository.saveAll(Lists.newArrayList(category1,category2,category3,category4));

    }

    @Test
    public void test2(){
        //update
        //1. 수정할레코드를 조회
        CategoryEntity category = repository.findById(2L).get();
        System.out.println(category);

        //2. setter메소드를 호출해서 변경
        category.setCategoryName(&quot;후드티&quot;);
        category.setInfo(&quot;스투시와 나이키&quot;);

        //3.save호출
        //save메소드는 객체를 새롭게 만들어서 작업하는 경우 insert문이 만들어지고
        //조회된 객체의 setter메소드를 호출해서 값을 변경하는 경우에는 update문이 만들어진다.
        //=&gt;JPA내부에서 최초로 만들어진 객체의 이미지를 저장하고 있다가 변경되면 update호출
        repository.save(category);
    }

    @Test
    public void test3(){
        List&lt;CategoryEntity&gt; list = repository.findByCategoryNameContaining(&quot;가&quot;);
        System.out.println(list);
    }
}</code></pre>
<p><a href="https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html">https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html</a></p>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/7036723a-5d6d-4c40-b741-4e2078b22348/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/5728e1ad-657c-4273-adc6-8ad1c76c4f04/image.png" alt=""></p>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JPA]]></title>
            <link>https://velog.io/@brave_chicken/JPA-c227511p</link>
            <guid>https://velog.io/@brave_chicken/JPA-c227511p</guid>
            <pubDate>Tue, 18 Jun 2024 08:53:25 GMT</pubDate>
            <description><![CDATA[<h2 id="양방향관계에서-여러데이터-삽입조회">양방향관계에서 여러데이터 삽입,조회</h2>
<h3 id="deptentity">DeptEntity</h3>
<pre><code class="language-java">@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = &quot;mydept&quot;)
public class DeptEntity {
    @Id
    @GeneratedValue
    @Column(name = &quot;deptNo&quot;)
    private Long id;
    private String name;
    private String mgr;
    //양방향관계에서는 항상 기준이 되는 엔티티는 외래키 테이블을 표현한 엔티티
    //현테이블과 매핑되는 테이블이 엔티티에서 어떤 컬럼명으로 명시되어 있는지 정의
    //양방향에서는 mappedBy 속성을 이용해서 내가 뭐에 의해서 매핑이 됐는지 명시
    //상대엔티티에서 현 엔티티를 매핑하고 있는 변수명을 정의
    //mappedBy가 정의되어있는 엔티티에서는 조회만 가능하도록 처리
    @OneToMany(mappedBy = &quot;dept&quot;)
    //양방향참조에서 toString을 호출하면 순환참조오류가 발생한다.
    //dept에서 emp의 toString을 호출하고 emp에서 dept의 toString을 호출한다.
    //직접호출하지않아도 JSON객체를 만들때 내부에서 toString을 호출하는 상황이 만들어진다.
    @ToString.Exclude //toString메소드에 해당컬럼을 포함하지 않겠다는 의미
    private List&lt;EmpEntity&gt; emplist = new ArrayList&lt;&gt;();

    public DeptEntity(String name, String mgr) {
        this.name = name;
        this.mgr = mgr;
    }
}
</code></pre>
<h3 id="empentity">EmpEntity</h3>
<pre><code class="language-java">//단방향으로 작업
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = &quot;myemp&quot;)
public class EmpEntity extends PublicInfoEntity {
    @Id
    private String userId;
    private String name;
    private String addr;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = &quot;userPrivateId&quot;)
    private PrivateInfoEntity infoEntity;


    public EmpEntity(String userId, String name, String addr, PrivateInfoEntity infoEntity) {
        this.userId = userId;
        this.name = name;
        this.addr = addr;
        this.infoEntity = infoEntity;
    }

    //경력사항은 한 사람이 여러 개 가질 수 있다.
    @OneToMany(mappedBy = &quot;emp&quot;, cascade = CascadeType.ALL)
//    @JoinColumn(name = &quot;userKey&quot;)
    private List&lt;HistoryEntity&gt; historylist = new ArrayList&lt;&gt;();

    @ManyToOne
    @JoinColumn(name = &quot;deptId&quot;)
    private DeptEntity dept;

    //양방향관계에서 주데이터 이외의 새로 추가된 데이터가 반영된다.
    public void changeVal(HistoryEntity history){
        historylist.add(history);
        history.setEmp(this);
    }

    //모든정보를 Emp에 저장하기
    //양방향관계에서 기본객체가 아닌 객체도 데이터가 반영될 수 있도록 처리하기
    public static EmpEntity buildEmpEntity(String userId, String name, String addr,
                                           PrivateInfoEntity infoEntity, List&lt;HistoryEntity&gt; historylist, DeptEntity dept){
        EmpEntity entity = new EmpEntity(userId,name,addr,infoEntity,dept);
        //historylist에서 history를 꺼내서 emp를 셋팅
        for (HistoryEntity history:historylist){
            entity.changeVal(history);
        }
        return entity;
    }

    public EmpEntity(String userId, String name, String addr, PrivateInfoEntity infoEntity, List&lt;HistoryEntity&gt; historylist) {
        this.userId = userId;
        this.name = name;
        this.addr = addr;
        this.infoEntity = infoEntity;
        this.historylist = historylist;
    }

    public EmpEntity(String userId, String name, String addr, PrivateInfoEntity infoEntity, DeptEntity dept) {
        this.userId = userId;
        this.name = name;
        this.addr = addr;
        this.infoEntity = infoEntity;
        this.dept = dept;
    }
}
</code></pre>
<h3 id="historyentity">HistoryEntity</h3>
<pre><code class="language-java">@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = &quot;myhistory&quot;)
public class HistoryEntity {
    @Id
    @GeneratedValue
    private Long historyId;
    private String company;
    private String content;

    @ManyToOne
    @JoinColumn(name = &quot;id&quot;)
    private EmpEntity emp;

    public HistoryEntity(String company, String content) {
        this.company = company;
        this.content = content;
    }
}
</code></pre>
<h3 id="jpawaytest">JPAWayTest</h3>
<pre><code class="language-java">@SpringBootTest
@Transactional
@Rollback(value = false)
class JPAWayTest {
    @PersistenceContext
    EntityManager entityManager;

    @Test
    public void test1() {
        //초기데이터 저장하기
        DeptEntity dept1 = new DeptEntity(&quot;전산실&quot;, &quot;RM&quot;);
        DeptEntity dept2 = new DeptEntity(&quot;인사팀&quot;, &quot;슈가&quot;);
        DeptEntity dept3 = new DeptEntity(&quot;기획실&quot;, &quot;뷔&quot;);

        entityManager.persist(dept1);
        entityManager.persist(dept2);
        entityManager.persist(dept3);
        //사원을 등록할 때 경력 사항을 같이 등록하기
        //파라미터로 전달 받은 부서 코드를 이용해서 부서 정보 조회
        PrivateInfoEntity privateInfo1 =
                new PrivateInfoEntity(&quot;bts1&quot;, &quot;태양과 듀엣&quot;, &quot;솔로&quot;);
        PrivateInfoEntity privateInfo2 =
                new PrivateInfoEntity(&quot;bts2&quot;, &quot;Seven&quot;, &quot;올림픽곡&quot;);
        PrivateInfoEntity privateInfo3 =
                new PrivateInfoEntity(&quot;bts3&quot;, &quot;춤모야&quot;, &quot;조교&quot;);
        PrivateInfoEntity privateInfo4 =
                new PrivateInfoEntity(&quot;bts4&quot;, &quot;제대했다&quot;, &quot;너무해&quot;);
        PrivateInfoEntity privateInfo5 =
                new PrivateInfoEntity(&quot;kbr&quot;, &quot;싱어송라이터&quot;, &quot;바람바람바람&quot;);

        //경력사항 3개
        List&lt;HistoryEntity&gt; historyEntityList = new ArrayList&lt;&gt;();
        historyEntityList.add(new HistoryEntity(&quot;A사&quot;, &quot;front개발&quot;));
        historyEntityList.add(new HistoryEntity(&quot;B사&quot;, &quot;Entity개발&quot;));
        historyEntityList.add(new HistoryEntity(&quot;C사&quot;, &quot;보안&quot;));


        EmpEntity emp1 = new EmpEntity(&quot;bts1&quot;, &quot;지민&quot;, &quot;광주&quot;
                , privateInfo1, historyEntityList, dept1);
        EmpEntity emp2 = new EmpEntity(&quot;bts2&quot;, &quot;정국&quot;, &quot;부산&quot;, privateInfo2, dept1);
        EmpEntity emp3 = new EmpEntity(&quot;bts3&quot;, &quot;제이홉&quot;, &quot;광주&quot;, privateInfo3, dept2);
        EmpEntity emp4 = new EmpEntity(&quot;bts4&quot;, &quot;석진&quot;, &quot;천안&quot;, privateInfo4, dept2);
        EmpEntity emp5 = new EmpEntity(&quot;kbr&quot;, &quot;범룡&quot;, &quot;청주&quot;, privateInfo5, dept3);

        entityManager.persist(emp1);
        entityManager.persist(emp2);
        entityManager.persist(emp3);
        entityManager.persist(emp4);
        entityManager.persist(emp5);

    }

    @Test
    public void test2() {
        //dept데이터 조회하기 : Dept -&gt; Emp
        //ctrl+alt+L
        //1번부서
        DeptEntity deptEntity = entityManager.find(DeptEntity.class, 1L);
        System.out.println(deptEntity);

        //양방향은 양쪽의 모든 엔티티에서 각자방향으로 객체를 접근할 수 있다.
        List&lt;EmpEntity&gt; emplist = deptEntity.getEmplist();
        for (EmpEntity emp : emplist) {
            System.out.println(emp + &quot;=&gt;&quot; + emp.getDept());
        }
    }

    @Test
    public void test3() {
        //emp조회 : Emp -&gt; Dept
        EmpEntity empEntity = entityManager.find(EmpEntity.class, &quot;bts1&quot;);
        System.out.println(empEntity);
        System.out.println(empEntity.getDept().getName());
    }

    @Test
    public void test4() {
        //새로운 사원을 등록
        DeptEntity dept = entityManager.find(DeptEntity.class, &quot;2&quot;);
        System.out.println(dept);
        List&lt;HistoryEntity&gt; historyEntityList = new ArrayList&lt;&gt;();

        historyEntityList.add(new HistoryEntity(&quot;D사&quot;, &quot;front react개발&quot;));
        historyEntityList.add(new HistoryEntity(&quot;E사&quot;, &quot;Entity개발&quot;));
        historyEntityList.add(new HistoryEntity(&quot;A사&quot;, &quot;보안개발&quot;));

        EmpEntity emp = new EmpEntity(&quot;bts7&quot;, &quot; 슈가&quot;, &quot;대구&quot;,
                new PrivateInfoEntity(&quot;bts7&quot;, &quot;화양연화&quot;, &quot;래퍼&quot;),
                historyEntityList, dept);
        entityManager.persist(emp);
    }

    @Test
    public void test5() {
        //새로 삽입된 데이터를 조회하기 - Emp기준
        EmpEntity empEntity = entityManager.find(EmpEntity.class, &quot;bts7&quot;);
        System.out.println(&quot;bts7의 부서정보=&gt;&quot;+empEntity.getDept());
    }

    @Test
    public void test6() {
        //새로 삽입된 데이터를 조회하기 - Dept 기준
        DeptEntity deptEntity = entityManager.find(DeptEntity.class, 2L);
        System.out.println(deptEntity);

        //양방향은 양쪽의 모든 엔티티에서 각자방향으로 객체를 접근할 수 있다.
        List&lt;EmpEntity&gt; emplist = deptEntity.getEmplist();
        for (EmpEntity emp : emplist) {
            System.out.println(emp.getUserId());
        }
    }
    @Test
    public void test7() {
        //양방향으로 매핑되어있는 객체는
        //방향시 연관관계에서 주인이 아닌 역방향에 관계를 설정해서 코드를 넣지 않는다.
        // - mapped by 가 정의되어있는 엔티티는 조회만한다.
        //주체가 아닌 것을 이용해서 insert를 했기 때문에 dept가 셋팅되지 않는다.
        EmpEntity emp = new EmpEntity(&quot;bts5&quot;, &quot; 뷔&quot;, &quot;서울&quot;,
                new PrivateInfoEntity(&quot;bts5&quot;, &quot;화랑&quot;, &quot;서진이네&quot;));
        entityManager.persist(emp);

        DeptEntity dept = new DeptEntity(&quot;TF팀&quot;,&quot;kbr&quot;);
        dept.getEmplist().add(emp);
        entityManager.persist(dept);
    }

    @Test
    public void test8() {
        DeptEntity dept = new DeptEntity(&quot;서비스팀&quot;,&quot;장동건&quot;);
        entityManager.persist(dept);

        EmpEntity emp = new EmpEntity(&quot;bts7&quot;, &quot;슈가&quot;, &quot;대구&quot;,
                new PrivateInfoEntity(&quot;bts7&quot;, &quot;화양연화&quot;, &quot;래퍼&quot;),dept);
        entityManager.persist(emp);
    }

    @Test
    public void test9() {
        DeptEntity dept = entityManager.find(DeptEntity.class, &quot;2&quot;);
        System.out.println(dept);
        List&lt;HistoryEntity&gt; historyEntityList = new ArrayList&lt;&gt;();

        historyEntityList.add(new HistoryEntity(&quot;D사&quot;, &quot;front react개발&quot;));
        historyEntityList.add(new HistoryEntity(&quot;E사&quot;, &quot;Entity개발&quot;));
        historyEntityList.add(new HistoryEntity(&quot;A사&quot;, &quot;보안개발&quot;));

        //주객체와 양방향매핑되는 객체에 변경된 내용을 반영시키기
        EmpEntity emp = EmpEntity.buildEmpEntity(&quot;lee2&quot;, &quot;이민호&quot;, &quot;서울&quot;,
                new PrivateInfoEntity(&quot;lee2&quot;, &quot;신의&quot;, &quot;푸른바다의전설&quot;),
                historyEntityList, dept);
        entityManager.persist(emp);
    }
}</code></pre>
<hr>
<h2 id="적용실습-in-erp">적용실습 in erp</h2>
<h3 id="디렉토리구조">디렉토리구조</h3>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/cffcc6e1-b25b-4f94-9e09-9c5afd4d2b1c/image.png" alt=""></p>
<h3 id="categorycontroller">CategoryController</h3>
<pre><code class="language-java">//view를 랜더링하는 컨트롤러
@Controller
@RequestMapping(&quot;/category&quot;)
@RequiredArgsConstructor
public class CategoryController {
    private final CategoryService service;
    //page보기
    @GetMapping(&quot;write&quot;)
    public String categoryRegisterPage(){
        return &quot;manage/product/category&quot;;
    }
    @PostMapping(&quot;write&quot;)
    public String categoryRegister(CategoryRequestDTO inputdto){
        System.out.println(inputdto);
        service.write(inputdto);
        return &quot;manage/product/category&quot;;
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/361cba23-fea2-4f30-8a9a-8e0f891a5e2b/image.png" alt=""></p>
<h3 id="categoryhtml">category.html</h3>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;
      xmlns:layout=&quot;http://www.ultraq.net.nz/thymeleaf/layout&quot;
      layout:decorate=&quot;~{layout/mainLayout}&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;title&gt;Insert title here&lt;/title&gt;

&lt;/head&gt;

&lt;body&gt;
&lt;div class=&quot;container-fluid&quot; layout:fragment=&quot;content&quot;&gt;
    &lt;h1&gt;카테고리 등록&lt;/h1&gt;
    &lt;hr/&gt;
    &lt;form  class=&quot;form-horizontal&quot;  action=&quot;/erp/category/write&quot;   method=&quot;POST&quot; name=&quot;myform&quot;&gt;
        &lt;fieldset&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;!-- 카테고리명--&gt;
                &lt;div&gt;&lt;a href=&quot;/erp/catgory/list&quot;&gt;카테고리목록&lt;/a&gt;&lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;!-- 카테고리명--&gt;
                &lt;label class=&quot;control-label col-sm-2&quot; for=&quot;categoryName&quot;&gt;카테고리명&lt;/label&gt;
                &lt;div class=&quot;col-sm-3&quot;&gt;
                    &lt;input type=&quot;text&quot; id=&quot;categoryName&quot; name=&quot;categoryName&quot;
                           placeholder=&quot;카테고리명&quot;
                           class=&quot;form-control&quot;  &gt;

                &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;!-- 비고--&gt;
                &lt;label class=&quot;control-label col-sm-2&quot; for=&quot;info&quot;&gt;비고&lt;/label&gt;
                &lt;div class=&quot;col-sm-3&quot;&gt;
                    &lt;input type=&quot;text&quot; id=&quot;info&quot; name=&quot;info&quot;
                           placeholder=&quot;비고&quot;
                           class=&quot;form-control&quot;  &gt;

                &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;!-- Button --&gt;
                &lt;div class=&quot;col-sm-3 col-sm-offset-2&quot;&gt;
                    &lt;input type=&quot;submit&quot; value=&quot;등록하기&quot; class=&quot;btn btn-success&quot;/&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/fieldset&gt;
    &lt;/form&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 id="categorydaoimpl">CategoryDAOImpl</h3>
<pre><code class="language-java">@Repository
@RequiredArgsConstructor
public class CategoryDAOImpl implements CategoryDAO{
    //스프링프레임워크가 CategoryRepository의 구현체를 만들어서 autowired한다.
    private final CategoryRepository repository;

    @Override
    public void write(CategoryEntity category) {
        //create
        repository.save(category);
    }

    @Override
    public List&lt;CategoryEntity&gt; findAll() {
        //List
        return repository.findAll();
    }

    @Override
    public List&lt;CategoryEntity&gt; pagingFindAll() {
        return List.of();
    }

    @Override
    public CategoryEntity findById(long categoryId) {
        //read
        return repository.findById(categoryId).get();
    }
}</code></pre>
<h3 id="categoryserviceimpl">CategoryServiceImpl</h3>
<pre><code class="language-java">@Service
@RequiredArgsConstructor
public class CategoryServiceImpl implements CategoryService{
    private final CategoryDAO dao;
    @Override
    public void write(CategoryRequestDTO category) {
        //컨트롤러에서 넘겨받은 CategoryRequestDTO를 entity로 변환해서 넘기기
        //step01 - 생성자를 이용해서 직접 변경
        CategoryEntity entity = new CategoryEntity(category.getCategoryName(),
                                                 category.getInfo());
        dao.write(entity);
    }

    @Override
    public List&lt;CategoryResponseDTO&gt; findAll() {
        return List.of();
    }

    @Override
    public List&lt;CategoryResponseDTO&gt; pagingFindAll() {
        return List.of();
    }

    @Override
    public CategoryResponseDTO findById(long categoryId) {
        //Entity를 DTO로 변환해서 넘기기
        //step2 builder를 활용해서 작업하기
        CategoryEntity entity = dao.findById(categoryId);

        return CategoryResponseDTO.builder()
                .categoryId(entity.getCategoryId())
                .categoryName(entity.getCategoryName())
                .info(entity.getInfo())
                .build();
    }
}</code></pre>
<h3 id="categoryresponsedto">CategoryResponseDTO</h3>
<pre><code class="language-java">@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class CategoryResponseDTO {
    private Long categoryId;
    private String categoryName;
    private String info;
}</code></pre>
<h3 id="categoryrequestdto">CategoryRequestDTO</h3>
<pre><code class="language-java">@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class CategoryRequestDTO {
    private String categoryName;
    private String info;

}</code></pre>
<h3 id="categoryentity">CategoryEntity</h3>
<pre><code class="language-java">@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = &quot;category&quot;)
public class CategoryEntity {
    @Id
    @GeneratedValue
    private Long categoryId;
    private String categoryName;
    private String info;

    public CategoryEntity(String categoryName, String info) {
        this.categoryName = categoryName;
        this.info = info;
    }
}</code></pre>
<h3 id="categoryapicontroller">CategoryAPIController</h3>
<pre><code class="language-java">//api패키지의 모든 컨트롤러는 RestController
//JSON을 리턴하는 메소드
@RestController
@RequiredArgsConstructor
@RequestMapping(&quot;/api&quot;)
//로그기록
@Slf4j
public class CategoryAPIController {
    private final CategoryService categoryService;
    //카테고리를 추가하기 위한 데이터를 JSON으로 입력받고 싶은 경우
    //JSON으로 입력데이터를 만들어서 요청하면 스프링이 DTO로 변환
    //작업이 완료되면 성공완료됐는지만 넘기기
    //@RequestBody ---&gt; json데이터 -&gt; DTO로 변환해서 매개변수에 전달
    //@RequestBody ---&gt; 자바객체 -&gt; json데이터로 변환해서 응답
    @PostMapping(&quot;/category/insert&quot;)
    public ResponseEntity&lt;?&gt; insert(@RequestBody CategoryRequestDTO inputdata){
        System.out.println(inputdata);
        categoryService.write(inputdata);
        //ResponseEntity는 상태코드와 응답데이터의 본문을 설정
        //성공응답을 200 응답을 생성하고 별도의 본문없이 응답을 반환 - ok메시지
       // return ResponseEntity.ok().build(); -&gt;원래 이렇게하면됨 밑은 ok사인 찍고싶어서하는것
        return ResponseEntity.ok(HttpStatus.OK);
    }
    @GetMapping(&quot;/category/{categoryId}&quot;)
    public CategoryResponseDTO read(@PathVariable(&quot;categoryId&quot;) String catrgoryId){
        return categoryService.findById(Long.parseLong(catrgoryId));
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/brave_chicken/post/352a2f56-4ec0-4877-a7e3-415912a1a033/image.png" alt="">
<img src="https://velog.velcdn.com/images/brave_chicken/post/d18bcbb6-4219-4b7b-bbac-1440d3e5b869/image.png" alt=""></p>
<p>본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.</p>
]]></description>
        </item>
    </channel>
</rss>