<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yujinet</title>
        <link>https://velog.io/</link>
        <description>에러제조기 좀좀따리 지식...</description>
        <lastBuildDate>Tue, 16 Dec 2025 08:51:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yujinet</title>
            <url>https://velog.velcdn.com/images/youjininny__/profile/9924870a-171e-458a-81ff-200fd60f8e57/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yujinet. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/youjininny__" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[URL 자체는 일치한데  서버에서 검색이 안될 경우 (한글 path segment  오류)]]></title>
            <link>https://velog.io/@youjininny__/URL-%EC%9E%90%EC%B2%B4%EB%8A%94-%EC%9D%BC%EC%B9%98%ED%95%9C%EB%8D%B0-%EC%84%9C%EB%B2%84%EC%97%90%EC%84%9C-%EA%B2%80%EC%83%89%EC%9D%B4-%EC%95%88%EB%90%A0-%EA%B2%BD%EC%9A%B0-%ED%95%9C%EA%B8%80-path-segment-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@youjininny__/URL-%EC%9E%90%EC%B2%B4%EB%8A%94-%EC%9D%BC%EC%B9%98%ED%95%9C%EB%8D%B0-%EC%84%9C%EB%B2%84%EC%97%90%EC%84%9C-%EA%B2%80%EC%83%89%EC%9D%B4-%EC%95%88%EB%90%A0-%EA%B2%BD%EC%9A%B0-%ED%95%9C%EA%B8%80-path-segment-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Tue, 16 Dec 2025 08:51:16 GMT</pubDate>
            <description><![CDATA[<p>서버 API 호출 시 URL도 맞고 컨트롤러도 정상인데, 이상하게 400 Bad Request가 떨어지는 상황을 겪어본 적이 있을 것입니다. 특히 한글 검색어나 특수 문자를 path parameter에 넣을 때 이런 문제가 자주 발생합니다. 이번 글에서는 왜 경로 파라미터 방식이 특정 서버 환경에서 막히는지, 그리고 쿼리 방식으로 바꿨을 때 문제가 해결되는 이유를 실제 예시와 함께 상세히 설명합니다. 또한, %EC%98%A4 같은 퍼센트 인코딩 문제와 WAF(Web Application Firewall), 프록시 서버가 개입하며 발생하는 오류의 메커니즘까지 이해할 수 있도록 풀어드리겠습니다.</p>
<h2 id="1한글-path-parameter가-waf프록시에서-400을-일으키는-이유">1.한글 Path Parameter가 WAF/프록시에서 400을 일으키는 이유</h2>
<p>1) 경로 파라미터 방식은 왜 위험 요소로 취급될까?</p>
<p>경로(path segment)에 한글이나 특수 문자가 포함된 URL은 보안 로드밸런서/WAF등 입장에서 “위험 요청”으로 간주되기 쉽습니다.
예를 들어 다음 요청을 보겠습니다.</p>
<pre><code>GET /community/search/오</code></pre><p>사람이 보기엔 아무 문제 없어 보이지만, <strong>네트워크 장비나 WAF는</strong> <strong>‘비 ASCII 문자’</strong> 가 들어간 경로 자체를 의심하는 경우가 많습니다. 마치 택배 주소에 외계어가 끼어 있으면 시스템이 자동으로 스캔하는 것처럼요.</p>
<p>보안 장비들은 보통 아래와 같은 패턴에 민감하게 반응합니다.</p>
<pre><code>1. URL 경로에 비정상적인 문자 포함

2. 퍼센트 인코딩이 제대로 되지 않은 상태로 전달된 요청

3. 세그먼트가 비정상적으로 짧거나 길 때

4. 한글·일본어·중국어가 포함된 경우 (일부 구형 장비에서 오탐 발생)</code></pre><p>즉, 개발 서버는 멀쩡한데, 서버 앞단의 WAF/LB가 먼저 400을 던져 버리는 구조입니다.</p>
<h2 id="2-퍼센트-인코딩이-안-되어-있으면-더욱-문제가-커진다">2) 퍼센트 인코딩이 안 되어 있으면 더욱 문제가 커진다</h2>
<p>브라우저와 HTTP 표준에서는 한글 path segment를 반드시 퍼센트 인코딩 해야 합니다.</p>
<p>예:
오 → %EC%98%A4</p>
<p>따라서 아래 요청이 맞는 형식입니다.</p>
<pre><code>GET https://서버/community/search/%EC%98%A4</code></pre><p>하지만 많은 프록시나 WAF는 퍼센트 인코딩 되어 있어도 경로에 인코딩 문자열이 들어간 것을 위험하다고 판단해 요청 자체를 차단하기도 합니다. 특히 AWS WAF, Cloudflare 일부 룰, F5 ASM 등에서 이런 일이 자주 발생합니다.</p>
<h2 id="3-쿼리-방식은-왜-안전한가">3) 쿼리 방식은 왜 안전한가?</h2>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/881b0ab1-265f-4b34-b190-02ee9ce3006f/image.png" alt=""></p>
<p>같은 요청이라도 다음처럼 쿼리 파라미터로 보내면 대부분의 보안 장비가 허용합니다.</p>
<pre><code>GET https://서버주소/community?search=오</code></pre><p>또는 퍼센트 인코딩 버전:</p>
<pre><code>GET https://서버주소/community?search=%EC%98%A4</code></pre><p>쿼리는 검색 조건·필터링에서 흔히 쓰이기 때문에, 보안 장비들도 기본적으로 “정상 요청”으로 간주합니다.</p>
<h3 id="2-js-기반-서버-기준-쿼리-방식이-가장-올바른-해결책인-이유">2. JS 기반 서버 기준 쿼리 방식이 가장 올바른 해결책인 이유</h3>
<p>1) 이미 컨트롤러에서 쿼리 방식이 준비되어 있다</p>
<p>작성된 NestJS 컨트롤러에는 이미 다음 메서드가 존재합니다.</p>
<pre><code>@Get()
async listBoard(@Query() dto: SearchBoardRequestDto): Promise&lt;SearchBoardResponseDto&gt; {
  return this.communityService.searchBoard(dto);
}</code></pre><p>즉, 서버에서 쿼리 방식 호출을 기본으로 지원하고 있습니다.</p>
<p>이를 클라이언트에서 이렇게 호출할 수 있습니다:</p>
<pre><code>GET https://api.ieg-lab.com/community?search=오</code></pre><p>페이지네이션도 가능:</p>
<pre><code>
GET https://api.ieg-lab.com/community?search=오&amp;skip=0&amp;take=10</code></pre><p>이 방식은 path segment에 민감한 WAF에서 훨씬 안전하게 통과합니다.</p>
<h3 id="2-postman으로-아래-두-가지를-비교-테스트해보세요">2) Postman으로 아래 두 가지를 비교 테스트해보세요</h3>
<p>GET <a href="https://api.ieg-lab.com/community?search=%EC%98%A4">https://api.ieg-lab.com/community?search=오</a></p>
<p>GET <a href="https://api.ieg-lab.com/community?search=%EC%98%A4">https://api.ieg-lab.com/community?search=%EC%98%A4</a></p>
<p>➜ 1번이 정상 동작하면?</p>
<p>프론트에서도 반드시 쿼리 방식으로 전환해야 합니다.</p>
<p>➜ 둘 다 막힌다면?</p>
<p>그건 WAF 정책 문제이므로 로드밸런서·보안팀 로그를 확인해야 합니다.</p>
<p>3.
(선택) 그래도 /community/search/오 같은 Path 방식을 유지하고 싶다면</p>
<p>1) 퍼센트 인코딩된 URL을 사용하시면 됩니다.</p>
<pre><code>https://api.ieg-lab.com/community/search/%EC%98%A4</code></pre><h2 id="4-프론트엔드에서는-어떻게-수정해야-할까">4. 프론트엔드에서는 어떻게 수정해야 할까?</h2>
<p>❌ 기존(문제 발생 가능)
fetch(<code>/community/search/${searchKeyword}</code>);</p>
<p>✅ 수정(완전 안전)
fetch(<code>/community?search=${encodeURIComponent(searchKeyword)}</code>);</p>
<p>이 방식은:</p>
<p>보안 장비에서 막히지 않고</p>
<p>한글·특수문자·이모지 모두 정상 처리가 되며</p>
<p>JS DTO 기반의 Query Validation과도 자연스럽게 연동이 됩니다.</p>
<p>마무리</p>
<p>이번 글에서는 400 Bad Request가 서버 로직 문제가 아닌, WAF·프록시·로드밸런서 등 네트워크 보안 계층에서 발생하는 경우에 대해 자세히 설명했습니다. 특히 한글이 포함된 path parameter가 보안 장비에서 차단되는 사례가 매우 흔하다는 점, 그리고 
<strong><em>이를 해결하는 가장 안전한 방식은 쿼리 방식(?search=...)으로 전환하는 것임을</em></strong> 확인했습니다.</p>
<p>NestJS에서도 이미 쿼리 방식을 지원하고 있으므로, 프론트에서도 encodeURIComponent를 사용해 쿼리 파라미터로 보내면 문제 없이 검색 기능을 안정적으로 운영할 수 있습니다.! 감사합니다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[간단하게 만들게된 토이 프로젝트]]></title>
            <link>https://velog.io/@youjininny__/%EC%A3%BC%EB%A7%90%EC%97%90-5%EC%8B%9C%EA%B0%84-%ED%88%AC%EC%9E%90-%ED%95%98%EA%B3%A0-%EB%A7%8C%EB%93%A0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</link>
            <guid>https://velog.io/@youjininny__/%EC%A3%BC%EB%A7%90%EC%97%90-5%EC%8B%9C%EA%B0%84-%ED%88%AC%EC%9E%90-%ED%95%98%EA%B3%A0-%EB%A7%8C%EB%93%A0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</guid>
            <pubDate>Sun, 07 Dec 2025 06:37:40 GMT</pubDate>
            <description><![CDATA[<p>개발하면서 항상 느꼈던 불편함이 있었습니다.
툴마다 단축키가 다르고,
Mac / Windows가 또 다르고,
정리된 자료는 많은데 “서비스에 바로 쓸 수 있는 구조”는 거의 없다는 점이었습니다.</p>
<p>그래서 직접 만들었습니다. (아래 링크)
<a href="https://main.d3kod2wksckcvr.amplifyapp.com/">https://main.d3kod2wksckcvr.amplifyapp.com/</a></p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/8e5cd409-9836-444f-8ad7-63b6ad1bb095/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/cce92fec-6e3f-48db-96fb-783e7cf9b76f/image.png" alt=""></p>
<h2 id="프로젝트-핵심-목적">프로젝트 핵심 목적</h2>
<p>“모든 주요 개발/디자인 툴의 단축키를
Windows / macOS 완전 분리 + 통합 데이터 구조로 제공하는 프로젝트”</p>
<p>이 프로젝트는 단순 정리 문서가 아니라,
웹 / 앱 / 서비스에 바로 연동 가능한 실사용 데이터셋입니다.</p>
<h1 id="지원-툴">지원 툴</h1>
<ul>
<li>VS Code</li>
<li>IntelliJ</li>
<li>Figma</li>
<li>Photoshop</li>
<li>Illustrator</li>
<li>Premiere Pro</li>
</ul>
<p>모든 툴이 아래와 같은 통일된 구조를 가집니다.</p>
<p>즉,</p>
<p>✅ Windows / macOS 완전 분리</p>
<p>✅ 실무에서 실제로 쓰는 단축키만 정리</p>
<h2 id="앞으로-추가-예정">앞으로 추가 예정</h2>
<p>After Effects</p>
<p>Affinity Photo &amp; Designer</p>
<p>Final Cut Pro</p>
<h2 id="이-프로젝트를-통해-얻고-싶은-것">이 프로젝트를 통해 얻고 싶은 것</h2>
<p>개발자/디자이너의 툴 학습 비용 감소</p>
<p>작업 속도 향상</p>
<p>단축키 기반 UX 실험</p>
<p>실제 프로덕트로의 확장</p>
<p>🚀 이 프로젝트는 계속 확장 중입니다.
피드백, 개선 제안, 협업 모두 환영합니다.!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[권한이 없다니!!! 접근을 못한다니!! 
(conn=19) Access denied for user 'root'@'localhost']]></title>
            <link>https://velog.io/@youjininny__/%EA%B6%8C%ED%99%98%EC%9D%B4-%EC%97%86%EB%8B%A4%EB%8B%88-%EC%A0%91%EA%B7%BC%EC%9D%84-%EB%AA%BB%ED%95%9C%EB%8B%A4%EB%8B%88-conn19-Access-denied-for-user-rootlocalhost</link>
            <guid>https://velog.io/@youjininny__/%EA%B6%8C%ED%99%98%EC%9D%B4-%EC%97%86%EB%8B%A4%EB%8B%88-%EC%A0%91%EA%B7%BC%EC%9D%84-%EB%AA%BB%ED%95%9C%EB%8B%A4%EB%8B%88-conn19-Access-denied-for-user-rootlocalhost</guid>
            <pubDate>Thu, 28 Aug 2025 04:36:59 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/youjininny__/post/3fa82235-8ec7-4ac8-8ba6-7fa79c2ce6a2/image.png" alt=""></p>
<p>회사에 들어와서 mac을 처음 사용해보니 여태것 window만 쓰다가 mac을 쓰려니 사소한 단축키 부터, 설치나 환경변수 설정 까지 처음하다보니 낯설게 느껴지기도 하지만 특유의 mac ui가 맘에 들어 만족 중입니다!</p>
<p>암튼 </p>
<p>DBeaver를 사용해서 maria db를 연결 하려고 하니 위에 사진과 같은 오류가 계속해서 발생하고 있었습니다..</p>
<p>gpt : 권환문제(대에충 해결 할 수 있어보이는 명령어 제공), 구글링 : 권환문제(오류 원인과 나와같은 오류들을 대응 했던 사람들의 블로그 제공) </p>
<p>이런문제들은 gpt보다 구글링을 통해 블로그를 보면서 해결하는게 좋다고 생각하는 저의 자칭 빅데이터를 기반으로 다른 블로그를 참고하여 이 오류를 해결해 보겠습니다.</p>
<p><a href="https://stackoverflow.com/questions/62231627/access-denied-for-user-rootlocalhost-in-dbeaver">https://stackoverflow.com/questions/62231627/access-denied-for-user-rootlocalhost-in-dbeaver</a>
역시 스택오버플로우를 보니 저와 같은 오류를 발견한 사람이 있었습니다..
.
.
.
아 다른 경우네요..
더 찾아보니
<a href="https://wakestand.tistory.com/495">https://wakestand.tistory.com/495</a> 제가 발생한 오류와 완전히 비슷한 오류를 발견 하였습니다!</p>
<p>아 역시 mariadb 자체 권환 문제인가 싶어서, mariadb는 workbanch가 따로 없으니 cli를 통해 쿼리문을 작성하여 권환을 주려고 하였습니다!</p>
<p>하지만 제가 어떠한 명령어를 사용해도 먹히지 않았습니다..</p>
<p><a href="https://dbeaver.com/docs/dbeaver/Database-driver-MariaDB/#mariadb-connection-settings">https://dbeaver.com/docs/dbeaver/Database-driver-MariaDB/#mariadb-connection-settings</a> 공식 페이지 인데 이글도 참고!!</p>
<h2 id="삽질-끝에">삽질 끝에...</h2>
<p>결국에는 기존에 maria db 를 밀고 다시 다운로드 하였습니다.. 많은 블로그를 보니 다들 그렇게 하시더라구요... </p>
<p>암튼 정상적으로 maria db 와 연결되어
<img src="https://velog.velcdn.com/images/youjininny__/post/a0103f4a-6e72-4cfc-b05e-5ebdd5eaeb3f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/8a3e824b-9107-42b0-a299-a07c76abe3eb/image.png" alt=""></p>
<p>이렇게 사용할 수 있게 되었습니다!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[GitHub OAuth 연동 삽질기: 로컬은 되는데 서버에선 안될 때 ]]></title>
            <link>https://velog.io/@youjininny__/GitHub-OAuth-%EC%97%B0%EB%8F%99-%EC%82%BD%EC%A7%88%EA%B8%B0-%EB%A1%9C%EC%BB%AC%EC%9D%80-%EB%90%98%EB%8A%94%EB%8D%B0-%EC%84%9C%EB%B2%84%EC%97%90%EC%84%A0-%EC%95%88%EB%90%A0-%EB%95%8C</link>
            <guid>https://velog.io/@youjininny__/GitHub-OAuth-%EC%97%B0%EB%8F%99-%EC%82%BD%EC%A7%88%EA%B8%B0-%EB%A1%9C%EC%BB%AC%EC%9D%80-%EB%90%98%EB%8A%94%EB%8D%B0-%EC%84%9C%EB%B2%84%EC%97%90%EC%84%A0-%EC%95%88%EB%90%A0-%EB%95%8C</guid>
            <pubDate>Sun, 08 Jun 2025 13:35:34 GMT</pubDate>
            <description><![CDATA[<p>GitHub OAuth 연동 작업을 진행하면서 예상치 못한 오류가 발생했다. 로컬 환경에서는 잘 동작하는데, 배포 서버(ECS)에서는 이상하게도 인증이 실패하는 문제가 있었다. 처음엔 클라이언트 ID 문제인가 싶어서 헤맸는데, 문제의 원인은 생각보다 단순했다.</p>
<h4 id="github-인증-flow-연결하기">GitHub 인증 flow 연결하기</h4>
<p>처음엔 GitHub 클라이언트 ID를 발급받고, 아래와 같은 URL로 리디렉션되도록 구성했다.</p>
<blockquote>
<p>밑에 url 코드는 내가 개발하고 있는 gitmago 서비스의 github 연동 url 이다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/741e868d-e550-4f4e-aaa1-f10d29c183d1/image.png" alt=""></p>
<pre><code>https://github.com/login/oauth/authorize?client_id=Ov23liG2nzd77CtuJ9cZ&amp;redirect_uri=https://www.gitmago.com/auth/github/callback&amp;scope=read:user
</code></pre><p>연동을 시도하면 자동으로 auth/github/callback 엔드포인트로 이동되는데, 서버 코드에는 아직 access token을 처리하는 로직이 빠져있었다. 따라서 다음과 같이 코드를 받아 처리하는 로직을 추가했다.</p>
<p>.</p>
<pre><code>@GetMapping(&quot;/auth/github/callback&quot;)
public ResponseEntity&lt;?&gt; githubCallback(@RequestParam(&quot;code&quot;) String code) {
    // code를 받아 access token 발급 로직 처리
}
</code></pre><p><del>#### 위에 로직처럼 get 매서드를 통해 code를 파라미터로 받아 함수 안에서 처리 할 수 있게 구성 되어있음</del></p>
<p>처음에는 여기까지 아무 문제 없이 잘 작동하는 것처럼 보였다.</p>
<h3 id="문제-발생-서버에서만-인증-실패">문제 발생... 서버에서만 인증 실패?</h3>
<p>하지만 실제 배포 환경에서 테스트해보니 인증이 제대로 되지 않았다. 클라이언트 ID도 정확하고, redirect URI도 맞게 설정되어 있었는데 말이다.</p>
<p>로컬에서는 모든 게 정상 작동하는데, 서버만 문제라니... 의심 가는 부분이 생기기 시작했다.</p>
<h3 id="원인은-이미지였다-docker에서-깨졌던-build">원인은 이미지였다... Docker에서 깨졌던 build</h3>
<p>결국 문제의 원인은 이미지 빌드 과정에서 어노테이션이 누락되었기 때문이었다. 로컬에서는 개발 서버에서 직접 빌드하고 바로 띄우니까 문제가 없었지만, Docker 이미지로 빌드해서 ECR → ECS에 배포하는 과정에서 어노테이션을 포함한 클래스가 누락되었던 것이다.</p>
<p>다시 말해, 다음과 같이 어노테이션이 제대로 붙은 클래스를 포함시키지 못하고 있었다.</p>
<pre><code>@RequestParam(&quot;code&quot;) // ← 이 어노테이션!</code></pre><p>.
이를 수정한 후 이미지를 다시 빌드하고 ECR에 푸시한 뒤 ECS에 재배포하자, 문제는 깔끔하게 해결되었다.</p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/ead4f70f-d52a-49e7-9b1f-a8b0c90e7818/image.png" alt=""></p>
<h2 id="회고">회고</h2>
<p>OAuth 연동은 비교적 간단한 작업이라고 생각했는데, 배포 환경에서는 예상치 못한 오류가 나올 수 있다는 걸 다시 한 번 느꼈다. 특히 어노테이션 누락이나 빌드 환경의 차이로 인해 발생하는 이슈는 디버깅이 꽤 까다로울 수 있다.</p>
<p>앞으로는 Docker 빌드 시 누락되는 클래스나 어노테이션이 없는지 꼼꼼하게 체크해야겠다.!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[gitKraken] 프로젝트의 생산성을 올려주는 협업툴 사용해보기]]></title>
            <link>https://velog.io/@youjininny__/gitKraken-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%9D%98-%EC%83%9D%EC%82%B0%EC%84%B1%EC%9D%84-%EC%98%AC%EB%A0%A4%EC%A3%BC%EB%8A%94-%ED%98%91%EC%97%85%ED%88%B4-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@youjininny__/gitKraken-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%9D%98-%EC%83%9D%EC%82%B0%EC%84%B1%EC%9D%84-%EC%98%AC%EB%A0%A4%EC%A3%BC%EB%8A%94-%ED%98%91%EC%97%85%ED%88%B4-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Wed, 22 Jan 2025 08:26:34 GMT</pubDate>
            <description><![CDATA[<h1 id="gitkraken으로-git-관리-더-쉽게-하기">GitKraken으로 Git 관리 더 쉽게 하기</h1>
<p><strong>Git 사용, 아직도 어렵게 느껴지시나요?</strong><br>Git을 사용하면서 충돌과 관련된 고민을 단숨에 해결해 줄 <strong>GitKraken</strong> 입니다. 깔끔한 UI와 편리한 기능으로 Git 관리와 프로젝트 작업이 정말 쉬워질 겁니다.  </p>
<h2 id="gitkraken이란">GitKraken이란?</h2>
<p>GitKraken은 <strong>Git GUI 클라이언트</strong>로, 말 그대로 Git 작업을 훨씬 간단하고 직관적으로 만들어줍니다.<br>복잡한 명령어 대신 화면을 실시간으로 보면서 작업할 수 있는게 큰 메리트라고 할수 있습니다.<br><img src="https://velog.velcdn.com/images/youjininny__/post/856998d9-1ac6-4782-80a8-e4b0513c5132/image.png" alt="">
맨 오른쪽에 default Profile 이라고 뜨는데 계정과 연결이 되지 않아서 맨 오른쪽 처럼 뜹니다. 하단의 Interation 에 github를 클릭한후 계정과 연결하면 뜹니다. </p>
<h2 id="gitkraken-설치와-기본-설정">GitKraken 설치와 기본 설정</h2>
<h3 id="설치-방법">설치 방법</h3>
<ol>
<li><a href="https://www.gitkraken.com/">GitKraken 공식 웹사이트</a>에 접속해 주세요.  </li>
<li>사용하는 운영체제에 맞는 설치 파일을 다운로드하고 실행합니다.  </li>
<li>간단한 설정 과정을 거치면 됩니다.</li>
</ol>
<h3 id="초기-설정">초기 설정</h3>
<p>초반에 깃헙 계정을 연동 할때 SSL로 연동을 하였는데 오류가 굉장히 많이 났었다.</p>
<h2 id="gitkraken을-사용하고-좋은-점">GitKraken을 사용하고 좋은 점</h2>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/283e3b8f-ae98-4694-9b70-897e3332ef23/image.png" alt=""></p>
<h2 id="마무리하며">마무리하며</h2>
<p>소스트리? 형식의 프로그램을 처음 사용하였는데 사용하고 나니 한눈에 코드 수정 사항을 보게 되어 좋았던것 같습니다. 또한 gitkraken은 커밋이나 PR시 바로 변경 사항이 반영되어 편리 했던것 같습니다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Error] SLF4J(W): No SLF4J providers were found.]]></title>
            <link>https://velog.io/@youjininny__/Error-SLF4JW-No-SLF4J-providers-were-found</link>
            <guid>https://velog.io/@youjininny__/Error-SLF4JW-No-SLF4J-providers-were-found</guid>
            <pubDate>Wed, 11 Dec 2024 02:07:07 GMT</pubDate>
            <description><![CDATA[<p>스프링에서 SLF4J의존성을 추가하여 어플리케이션을 실행시킬때 </p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/d0a03348-dfcd-40b5-a77b-261d22abd2d1/image.png" alt=""></p>
<pre><code>SLF4J(W): No SLF4J providers were found.
SLF4J(W): Defaulting to no-operation (NOP) logger implementation
SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.</code></pre><p>라는 에러줄이 발생됩니다.</p>
<p>해당오류는 바인딩 버전이 맞지 않아 생기는 오류입니다.
의존성 파일이 존재하는 pom.xml이나 buildgradle파일에 들어가서 버전만 변경해주면 되는 오류 입니다.</p>
<p>저는 buildgradle파일에 의존성을 추가 하기때문에 buildgradle에서 변경해 주면 됩니다.</p>
<pre><code>dependencies {
    // Spring Boot Core Dependencies
    implementation &#39;org.springframework.boot:spring-boot-starter-web&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-thymeleaf&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-data-jpa&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-data-mongodb&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-security&#39;

    implementation &#39;jakarta.validation:jakarta.validation-api:3.0.2&#39;
    implementation &#39;org.hibernate.validator:hibernate-validator:8.0.1.Final&#39;

    implementation &#39;io.github.cdimascio:java-dotenv:5.3.1&#39;
    implementation &#39;com.fasterxml.jackson.core:jackson-databind:2.15.2&#39;

    implementation &#39;org.thymeleaf.extras:thymeleaf-extras-springsecurity6&#39;

    compileOnly &#39;org.projectlombok:lombok:1.18.30&#39;
    annotationProcessor &#39;org.projectlombok:lombok:1.18.30&#39;

    developmentOnly &#39;org.springframework.boot:spring-boot-devtools&#39;

    testImplementation &#39;org.springframework.boot:spring-boot-starter-test&#39;
    testImplementation &#39;org.springframework.security:spring-security-test&#39;

    // SLF4J API 추가
    implementation &#39;org.slf4j:slf4j-api:1.7.9&#39;

    implementation &#39;ch.qos.logback:logback-classic:1.4.11&#39;
}</code></pre><p>주석처리가 되어있는부분에 api:~ 부분이 원래는 api:2.0.0이런식으로 정의되어있었다면 바인딩버전을 맞추기위해 api:1.7.9로 변경하였더니 해당오류가 사라졌습니다.</p>
<p>버전 수정 : 2.0.0 -&gt; 1.7.9 로 변경</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[kotiln android native "R class not imort" 네이티브 개발 도중 R 클래스 안불러와지는 문제]]></title>
            <link>https://velog.io/@youjininny__/kotiln-android-native-R-class-not-imort-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EA%B0%9C%EB%B0%9C-%EB%8F%84%EC%A4%91-R-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%95%88%EB%B6%88%EB%9F%AC%EC%99%80%EC%A7%80%EB%8A%94-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@youjininny__/kotiln-android-native-R-class-not-imort-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EA%B0%9C%EB%B0%9C-%EB%8F%84%EC%A4%91-R-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%95%88%EB%B6%88%EB%9F%AC%EC%99%80%EC%A7%80%EB%8A%94-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Mon, 02 Dec 2024 10:41:47 GMT</pubDate>
            <description><![CDATA[<p>kotiln으로 안드로이드 개발도중 R 클래스가 제대로 import 되지 않는 문제가 생겼다. 아래 사진처럼 파일 구조도 정상적으로 구성되어있음에도 R클래스가 불러와지지 않아, 오류가 뜨고 화면에 이미지가 뜨지 않았다.</p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/03284579-98f9-4f77-acc4-2eba0c74ae78/image.png" alt=""></p>
<p>재점검 해보기 , 안드로이드스튜디오 기준으로 왼쪽 상단에 줄3개를 클릭하고
1.캐시 초기화 하고 restart 하기
<img src="https://velog.velcdn.com/images/youjininny__/post/f1db44c5-cf29-4e10-8d13-492cc26fbec1/image.png" alt=""></p>
<ol start="2">
<li>Gradle 리프레쉬하기
<img src="https://velog.velcdn.com/images/youjininny__/post/3e0852d3-50e2-4f56-81bb-a1bf8bbf1fe7/image.png" alt=""></li>
</ol>
<p>3.재빌드 하기
<img src="https://velog.velcdn.com/images/youjininny__/post/9bffac44-4873-48db-b985-8aab2b82edef/image.png" alt=""></p>
<p>이 3가지 방법을 실행 한다면 R클래스를 import 관련 문제를 해결할수있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[error] Call requires permission which may be rejected by userSecurityException More]]></title>
            <link>https://velog.io/@youjininny__/error-Call-requires-permission-which-may-be-rejected-by-userSecurityException-More</link>
            <guid>https://velog.io/@youjininny__/error-Call-requires-permission-which-may-be-rejected-by-userSecurityException-More</guid>
            <pubDate>Mon, 18 Nov 2024 03:07:10 GMT</pubDate>
            <description><![CDATA[<p>코틀린으로 네이티브 개발도중
<img src="https://velog.velcdn.com/images/youjininny__/post/a4965301-b929-4827-b3b3-3bea1354e902/image.png" alt="">
사진과 같은 오류를 발견하게 되었다.
오류메세지를 번역하자면 &quot;불러와서 수행하려고 하는데 권환을 얻지 못해 이를 올바르게 수행하지 못한다&quot; 라고 한다 </p>
<p>그럼 권환을 주면 해결될 일이다.
Add permission check 를 클릭하고 권한을 주고 , 
<img src="https://velog.velcdn.com/images/youjininny__/post/f10255cf-77f4-43cd-80f5-5cc078637bd4/image.png" alt="">
권한을 주게 되면 this 라는 매개변수로 받게되어 또 다른 오류가 생기게 되는데 ,자신이 설정한 매개변수로 값을 바꾸면 된다. 나는 context로 매개변수를 설정하였는데 this를 아래 사진과 같이
<img src="https://velog.velcdn.com/images/youjininny__/post/06265b49-9c5b-4a97-9152-26b6738bba8a/image.png" alt="">
context로 바꾸니 오류가 해결됬다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[java spring(2) JPA구조 살펴보기]]></title>
            <link>https://velog.io/@youjininny__/java-spring2-JPA%EA%B5%AC%EC%A1%B0-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@youjininny__/java-spring2-JPA%EA%B5%AC%EC%A1%B0-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Mon, 30 Sep 2024 07:31:44 GMT</pubDate>
            <description><![CDATA[<p>이번에 jpa를 통해 DB테이블을 생성하고 </p>
<p>question , answer 패키지를 아래와 같이 생성해주고
<img src="https://velog.velcdn.com/images/youjininny__/post/89ae409b-82e2-4f92-9688-e2b0027a2244/image.png" alt=""></p>
<p>Question.java 
Answer.java 이름에 자바클래스 파일을 생성 해줍니다.
<img src="https://velog.velcdn.com/images/youjininny__/post/55a9e500-d067-4f68-9d85-14791fe95706/image.png" alt=""></p>
<p>Answer.java 파일코드</p>
<pre><code>package com.AdA.backend.answer;

import java.time.LocalDateTime;

import org.springframework.data.annotation.CreatedDate;

import com.AdA.backend.question.Question;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;

import lombok.Getter;
import lombok.Setter;


@Getter
@Setter
@Entity

public class Answer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(columnDefinition = &quot;TEXT&quot;)
    private String content;

    @CreatedDate
    private LocalDateTime createDate;

    @ManyToOne
    private Question question;

}
</code></pre><p>Question.java 파일코드</p>
<pre><code>package com.AdA.backend.question;

import java.time.LocalDateTime;
import java.util.List;

import com.AdA.backend.answer.Answer;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
public class Question {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(length = 200)
    private String subject;

    @Column(columnDefinition = &quot;TEXT&quot;)
    private String content;

    // 필드 이름을 createdDate로 수정
    private LocalDateTime createdDate;

    @OneToMany(mappedBy = &quot;question&quot;, cascade = CascadeType.REMOVE)
    private List&lt;Answer&gt; answerList;
}

</code></pre><p>파일에 그대로 파일에 위와같은 코드를 수정해줍니다.
그러면 실제로  JPA 형식으로 복잡한 SQL 쿼리문 작성없이 DB테이블이 생성된겁니다. </p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/06869471-f078-4ebd-b8c8-2d37ebe02dc9/image.png" alt=""></p>
<h2 id="👉왜-jpa를-사용해야될까">👉왜 JPA를 사용해야될까?</h2>
<p>JPA는 반복적인 CRUD SQL을 처리해준다. JPA는 매핑된 관계를 이용해서 SQL을 생성하고 실행하는데, 개발자는 어떤 SQL이 실행될지 생각만하면 되고, 예측도 쉽게 할 수 있고 , 코드의 가독성 및 유지보수의 향상 , 데이터베이스 독립성 , 객체와 데이터베이스간의 매핑 , 자동화 된 데이터베이스 처리 다양한 측면에서 CRUD 작업을 처리하기에 편리 하기 때문에 사용 합니다.</p>
<p>코드를 순차적으로 살펴볼건데 </p>
<h3 id="answerjava-questionjava-클래스-파일에">Answer.java, Question.java 클래스 파일에</h3>
<p>사용되었던 , JPA 속성을 살펴볼거다.
<em>@Getter , @Setter , @Entity</em>  3개의 이노테이션 속성이 클래스 위에 있다.</p>
<p>각각의 어노테이션은 코드의 가독성을 높이고 , 개발자의 반복적인 작업을 줄여주는 데 도움을 준다. </p>
<h3 id="lombok--getter-와-setter">Lombok : @Getter 와 @Setter</h3>
<p>간단하게 생각하면 불필요한 코드 작성을 막아준다. 클래스 필드에 대해 자동으로 getter와 setter 매서드를 생성 해준다.
Entity_ 어노테이션은 테이블 처럼 취급 할 수 있다.</p>
<p>또한</p>
<h3 id="id">@Id</h3>
<p>primary key(기본키)로 취급 </p>
<h3 id="generatedvalue">@GeneratedValue</h3>
<p>기본키의 값을 어떻게 생성할지를 지정 </p>
<h3 id="manytoone">@ManyToOne</h3>
<p>한 엔터티가 여러개의 엔터티와 연결할수있는 일대 다 관계를 말함.
간단하게 외래키단하게 외래키(Foreign Key)를 말한다.</p>
<h3 id="createddate">@CreatedDate</h3>
<p>생성된 날짜와 시간을 자동으로 생성해주는 속성 (게시판,채팅)에 사용</p>
<h3 id="columnlength200">column(length(=200)</h3>
<p>컬럼 200자 내외로 길이 제한을 한다.</p>
<p>@속성의 이름을 지정해주고 private를 작성하고 , 그다음 컬럼에 자료형을 적어주고 컬럼의 명을 작성하면 컬럼이 자동으로 만들어진 것 이다.</p>
<pre><code>@column (추가적인 속성)
private String name; 이런식으로 작성하면 컬럼이 생성된것이다.</code></pre><h1 id=""></h1>
<h2 id="👉각각의-클래스를-확인하여-어떠한-컬럼이-만들어졌는지-확인하기">👉각각의 클래스를 확인하여 어떠한 컬럼이 만들어졌는지 확인하기</h2>
<p>각각의 클래스 jpa 파일을 살펴보면</p>
<h2 id="👉answerjava">👉Answer.java</h2>
<p>import로 필요한 라이브러리들을 불러와주고,
id , content , createtime , question 컬럼 4개를 만들어 주었다.</p>
<h2 id="👉questionjava">👉Question.java</h2>
<p>마찬가지로 import로 필요한 라이브러리를 불러와준다.
id, subject , content , createdDate , answerList 컬럼 5개를 만들어주었다.</p>
<p>이렇게 까지 하면 jpa를 통한 CRUD 구성의 DB 구축이 완료 되었다.</p>
<p>추가적으로 질문 사항이 있으시면 
discord : youjininny_ 로 연락주시면 됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[java spring(1) 세팅과 DB연결]]></title>
            <link>https://velog.io/@youjininny__/java-spring-%EA%B2%8C%EC%8B%9C%ED%8C%901</link>
            <guid>https://velog.io/@youjininny__/java-spring-%EA%B2%8C%EC%8B%9C%ED%8C%901</guid>
            <pubDate>Sun, 29 Sep 2024 23:50:43 GMT</pubDate>
            <description><![CDATA[<p>먼저
<a href="https://start.spring.io/">https://start.spring.io/</a> 사이트에 들어가면
<img src="https://velog.velcdn.com/images/youjininny__/post/9b9937dc-ca63-481c-b0b5-0a5b19b6c704/image.png" alt="">
위와 같은 페이지가 뜨게 됩니다.</p>
<p>Dependencies 의존성은 아래의 리스트 대로 추가해주시면 됩니다.
<img src="https://velog.velcdn.com/images/youjininny__/post/b31c3b2b-6a10-4966-b34d-4780d3763039/image.png" alt=""></p>
<p>코드를 application.properties 파일을 아래와 같이 그대로 복붙해줍니다.
spring.application.name=demo 은 폴더명으로 바꿔주고
spring.datasource.url=jdbc:h2:~/adabase 뒤에 adabase은 DB이름을 뜻합니다.
adabase하고 싶은 DB이름으로 지정해줍니다.</p>
<p>의존성에 대한 설명을 하면</p>
<h2 id="⭐️-spring-boot-devtools">⭐️ Spring Boot DevTools</h2>
<p>자동 재시작이 가능 하다 , spring 안에서 코드에 변경사항이 있을때 , 기존에는 서버를 껐다 켜야되지만 자동으로 변경사항을 반영을 해준다는 이점이 있다.</p>
<h2 id="⭐️-lombok">⭐️ Lombok</h2>
<p>lombok 라이브러리를 불러오면 @Getter, @Setter , @Data 같은 어노테이션만 붙이면 , 불필요한 코드들을 줄일수 있다. 그러므로 코드가 짧아지고 깔끔해지며 읽기 편해짐</p>
<h2 id="⭐️-validation">⭐️ validation</h2>
<p>사용자가 입력한 데이터가 올바른지 검사하는 확인함.</p>
<h2 id="⭐️-spring-data-jpa">⭐️ Spring Data JPA</h2>
<p>복잡한 SQL을 손으로 쓰지 않고 , 매서드만 호출하면 SQL을 만들어 준다.
예를 들어 , findByName(String name) 이라는 이름만으로도 이름으로 데이터를 찾을 수 있는 SQL이 형성되서 굳이 SQL Quary문을 작성하지 않아도 됨.</p>
<h2 id="⭐️-h2-database">⭐️ H2 Database</h2>
<p>연결할 데이터 베이스를 의존성에 추가를 하는 것인데 , 메모리를 통해서 DB를 사용하는것이기 때문에 속도가 매우 빠르고 테스트 하기에 적합하다.(임시데이터를 다룰때 편리함)</p>
<h2 id="⭐️-thymeleaf">⭐️ Thymeleaf</h2>
<p>서버 사이드 템플릿 엔진이다(대체로 테스트 할... html 화면 같은거?)</p>
<p>*<em>application.properties 파일 *</em></p>
<pre><code>spring.application.name=demo

#DATABASE
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.url=jdbc:h2:~/adabase
spring.datasource.driverClassName:org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

#JPA
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update  
# SQL Debug
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true    입력하세요</code></pre><p><img src="https://velog.velcdn.com/images/youjininny__/post/9c4653a4-d539-4197-a42e-88783da5b012/image.png" alt=""></p>
<p>C:\Users\user 이름 파일경로로 이동 한 다음 
&quot;adabase.mv.db&quot; 라는 이름을 텍스트 파일을 만들어주고 명을 변경해줍니다.
<img src="https://velog.velcdn.com/images/youjininny__/post/509e5089-bbdc-47a5-b01d-6a64661ae1bd/image.png" alt=""></p>
<p>아래와 같이 변경을 해주면 h2데이터베이스가 내 내장 하드드라이브에서 사용되는 DB가 만들어진거고, application.properties 파일을 위와 같이 수정해 줌으로써 연결이 된겁니다.</p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/6fd45f5e-cf00-49ca-b2da-2fb50e0b3694/image.png" alt="">
다음 DemoApplication파일을 우클릭해주고</p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/9603a856-1d09-4279-860f-90256a092a45/image.png" alt="">
RUN&#39;DemoApplication.main()&#39;을 실행해주고</p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/7da0ae42-130f-4734-98d4-2687479e4e20/image.png" alt="">
이런식으로 consloe에서 아래와 같이 뜨게 되는데 정상적으로 실행된것입니다.</p>
<h2 id="localhost8080h2-console을-브라우저-위에-검색해서-들어가시면">localhost:8080/h2-console을 브라우저 위에 검색해서 들어가시면</h2>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/220990ae-edca-453a-9540-ba3143d89c3d/image.png" alt="">
이런식으로 접속 콘솔이 뜨게 되면
JDBC URL &#39;/&#39;뒤에 부분을 &#39;adabase&#39; 로 하게 되면 DB에 들어가게 됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[빈의 순환참조(circular reference) 문제 Gradle jdk 버전 맞췄는데 계속오류뜨는 사람보세요.]]></title>
            <link>https://velog.io/@youjininny__/%EB%B9%88%EC%9D%98-%EC%88%9C%ED%99%98%EC%B0%B8%EC%A1%B0circular-reference-%EB%AC%B8%EC%A0%9C-Gradle-jdk-%EB%B2%84%EC%A0%84-%EB%A7%9E%EC%B7%84%EB%8A%94%EB%8D%B0-%EA%B3%84%EC%86%8D%EC%98%A4%EB%A5%98%EB%9C%A8%EB%8A%94-%EC%82%AC%EB%9E%8C%EB%B3%B4%EC%84%B8%EC%9A%94</link>
            <guid>https://velog.io/@youjininny__/%EB%B9%88%EC%9D%98-%EC%88%9C%ED%99%98%EC%B0%B8%EC%A1%B0circular-reference-%EB%AC%B8%EC%A0%9C-Gradle-jdk-%EB%B2%84%EC%A0%84-%EB%A7%9E%EC%B7%84%EB%8A%94%EB%8D%B0-%EA%B3%84%EC%86%8D%EC%98%A4%EB%A5%98%EB%9C%A8%EB%8A%94-%EC%82%AC%EB%9E%8C%EB%B3%B4%EC%84%B8%EC%9A%94</guid>
            <pubDate>Mon, 16 Sep 2024 18:29:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/youjininny__/post/80509b2d-b7d8-4fb9-ab3e-2c565c224ced/image.png" alt="">
Spring 공부를 하면서 회원가입/로그인을 구현하는 도중 , 서버를 실행시키려다 계속해서 JAVA21버전과 Gradle 버전이 호환이 되지 않는다는 오류가 계속해서 발생하였습니다.
Gradle 버전을 계속해서 업그레이드 하면서 맞추어 보았지만 
같은오류.........
빌드 메세지를 자세히 보는 순환참조문제 인것 같아 , 확인해 보니</p>
<blockquote>
<p>SecurityConfig 클래스에서 UserService빈을 참조하고 있고,
UserService 클래스에서 PasswordEncoder빈을 참조하고 있고,
PasswordEncoder 빈은 SecurityConfig에서 정의되어있습니다.</p>
</blockquote>
<p>결과적으로 SecurityConfig-&gt;UserService-&gt;SecurityConfig의 순환참조가 발생하였습니다.</p>
<h1 id="해결방법">해결방법</h1>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/d92f4e7d-8b76-459b-9599-b3bd1e4f3b78/image.png" alt="">
원래는 SecurutyConfig 클래스에서 불러와진던 PasswordEncoder를
<img src="https://velog.velcdn.com/images/youjininny__/post/25ea80d3-7b48-42f8-9f03-82960fff0549/image.png" alt="">
UserSerivce클래스에서 처리하게 코드를 바꾸었습니다.</p>
<h4 id="결론적으로-passwordencoder빈-생성위치를-userservice로-이동하여-순환참조를-제거-하였습니다">결론적으로 PasswordEncoder빈 생성위치를 UserService로 이동하여 순환참조를 제거 하였습니다.</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데이터 마이닝] Market-Basket-Model2, A-Priori algorithm , PCY]]></title>
            <link>https://velog.io/@youjininny__/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EC%B2%98%EB%A6%AC-Market-Basket-Model2-A-Priori-algorithm-PCY</link>
            <guid>https://velog.io/@youjininny__/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EC%B2%98%EB%A6%AC-Market-Basket-Model2-A-Priori-algorithm-PCY</guid>
            <pubDate>Sun, 21 Apr 2024 07:12:24 GMT</pubDate>
            <description><![CDATA[<h3 id="연관규칙-알고리즘-a-priori-a-multi-pass-algorithm">(연관규칙 알고리즘 )A-Priori: a multi-pass algorithm</h3>
<p>메인메모리에서 frequent itemset을 찾는 알고리즘 입니다.</p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/8b64f9a6-df7b-497f-b67a-1f7ea81b4693/image.png" alt=""></p>
<h2 id="쉽게-이해-하기-위한">쉽게 이해 하기 위한</h2>
<p>주어진 itemset I가 최소 s번 이상 나타난다고 가정해 봅시다. 그러면 itemset I의 부분집합 J는 최소 s번 이상 나타난다는 것을 의미합니다.</p>
<p>다시 말해, 만약 어떤 아이템 I가 최소 s개의 바스켓에 나타나지 않는다면, 즉 자주 등장하지 않는다면, I를 포함하는 어떤 pair도 s번 이상 나타날 수 없습니다.</p>
<p>예를 들어, {B}가 자주 등장하지 않는다면 {B,D}도 자주 등장하지 않습니다. 이는 {B}가 자주 등장하지 않으면 {B,D}와 같은 아이템셋은 전혀 자주 등장하지 않을 것이기 때문입니다.</p>
<p>따라서, 최소 s개의 바스켓이 자주 등장하지 않으면 {B},{BD}와 같은 아이템셋에 대한 탐색은 하지 않습니다. 이는 바로 가지치기를 의미합니다.</p>
<h2 id="첫번째-pass">첫번째 pass:</h2>
<p>첫 번째 패스에서는 각 바스켓을 순차적으로 읽으면서 메인 메모리에서 각 아이템이 몇 번 등장하는지를 셉니다. 이 과정에서는 singleton 아이템셋이 얼마나 자주 등장하는지를 확인합니다. 이때 필요한 메모리는 아이템의 개수만큼이 됩니다.</p>
<h2 id="두번째-pass">두번째 pass:</h2>
<p>첫 번째 패스에서는 데이터를 다시 처음부터 쭉 읽게 되는데, 이때는 pass1에서 frequent하다고 판단한 아이템들의 쌍에 대해서만 count를 합니다. 즉, pass1에서 자주 등장하는 것으로 확인된 아이템들에 대해서만 pair를 만들어서 그 쌍을 카운트합니다.</p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/aa8bb99d-d43a-4e49-9765-1c55027072a4/image.png" alt=""></p>
<p>메인 메모리 구조는 다음과 같습니다 , pass1에서는 메모리의 상단 영역에 각 개별 아이템의 카운트를 저장합니다. 이때 각 아이템의 카운트를 누적하고, 최소 s번 이상 등장하는 것으로 판단되는 frequent한 아이템들을 사용하여 가능한 모든 pair를 만듭니다. 그리고 이러한 pair의 카운트를 메모리 영역에서 세는 것이 pass2입니다.</p>
<h2 id="빈발하게-나타나는-singleton-item-과-pair의-count를-세는-방법">빈발하게 나타나는 singleton item 과 pair의 count를 세는 방법</h2>
<p>가장 많이 빈발하는 아이템을 찾은 후에는 이러한 빈발 아이템들을 기반으로 빈발 쌍의 후보를 골라냅니다. 이 후보 쌍들은 실제로 빈발한지를 카운트하여 확인하게 됩니다.
<img src="https://velog.velcdn.com/images/youjininny__/post/0c45bfb3-0008-4f79-9d43-f1c49384c1e5/image.png" alt=""></p>
<p>A-Priori 알고리즘은 Ck와 Lk를 반복하여 만드는 과정을 말합니다. 여기서 k가 2일 때 가장 많은 메모리가 필요하게 됩니다.</p>
<h1 id="pcypark-chen-yu-algorithm">PCY(park-chen-yu) Algorithm</h1>
<h2 id="a-priori-유사하지만-다른-점">A-priori 유사하지만 다른 점</h2>
<p>PCY(Principle of Counting with a Hash Table)는 A-Priori와 유사한 알고리즘이지만, 각각의 아이템 count를 세는 대신에 pair의 count를 세기 위한 해시 테이블을 유지합니다. 이 해시 테이블의 각 버킷은 해당 pair의 해시값을 가지고 있는 pair의 count를 포함하고 있습니다. A-Priori의 pass1에서 사용되지 않는 많은 메인 메모리 문제를 해결하기 위해, PCY에서는 각 pair를 해시하여 count가 s() 이상인지를 확인하는 것을 합니다.</p>
<h2 id="pcy-알고리즘을-사용하였을-때-좋은점">pcy 알고리즘을 사용하였을 때 좋은점</h2>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/b27cfc2e-6b20-4916-9dd9-7f1ac48c36ff/image.png" alt=""></p>
<p>PCY 알고리즘은 A-Priori와 다르게 개별적으로 빈발하는 아이템의 수가 많을 때에도 (2,3)과 (1,9)와 같은 쌍이 선발되지 않을 수 있습니다. PCY 알고리즘에서는 가장 작은 support 수를 지정하고, 쌍으로 묶은 후 해당 쌍의 Total count가 지정한 support 수를 넘지 못할 경우 탈락시킵니다. 즉, PCY 알고리즘은 A-Priori 알고리즘과 달리 개별 아이템의 쌍을 묶고, 최소 support에 미치지 못할 때 탈락한다는 점에서 다릅니다. 이는 PCY 알고리즘의 주된 아이디어라고 볼수 있습니다.</p>
<h2 id="pass-1-메모리-사용량을-줄일수-있다">pass 1 메모리 사용량을 줄일수 있다.</h2>
<ul>
<li>각각의 버킷은 해당 쌍이 frequent 한지 여부만을 중요시합니다</li>
<li>버킷 값이 1이면 해당 버킷은 frequent한 것을 나타내며, 그 bit 값이 0이면 frequent하지 않음을 나타냅니다.</li>
</ul>
<p>이러한 이유로 A-Priori 알고리즘에서는 버킷의 카운터를 약 32비트로 사용했지만, PCY 알고리즘에서는 1비트만으로도 frequent 여부를 구별할 수 있기 때문에 메모리 사용량을 크게 줄일 수 있습니다.</p>
<h2 id="pass-2-쌍이-두가지-조건을-만족-해야된다">pass 2 쌍이 두가지 조건을 만족 해야된다.</h2>
<ul>
<li>(i ,j ) 각각이 frequent 아이템 이어야 하고 ,</li>
<li>해당 쌍이 frequent한 버킷으로 해싱되어야 됩니다.</li>
</ul>
<p>만약에 (i)와 (j)가 frequent하지만 (i,j) 쌍이 frequent 하지 않으면 셀 필요가 없게 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/617bb7d9-6f27-4a86-b9a2-5bffbb0f40ea/image.png" alt=""></p>
<h3 id="메인메모리-구조">메인메모리 구조</h3>
<h1 id="중요한건-pcy-알고리즘을-활용한-변형-알고리즘">중요한건 PCY 알고리즘을 활용한 변형 알고리즘</h1>
<h2 id="멀티-스테이지"><strong>멀티 스테이지</strong></h2>
<p>변형 메모리  </p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/0af32a3d-37e9-4977-97c4-356d74624d94/image.png" alt=""></p>
<p>pass1에서는 pair의 수를 한 번 적어주고, pass2에서는 i와 j의 값이 모두 frequent한 조건을 만족할 때 실행됩니다. 그러나 이러한 조건을 만족하는 pair가 매우 적기 때문에, 각 버킷이 기여하는 pair의 수가 적어집니다. 결과적으로, 빈발하지 않지만 빈발한 것처럼 보이는 pair의 수를 줄일 수 있습니다.</p>
<p>PCY 알고리즘의 단점은 메모리가 한 번 더 사용된다는 것이지만, 까다로운 조건으로 인해 최종적으로 후보 pair의 수를 줄일 수 있어 더편리하고 효율적 입니다. 
pass3에서는 3가지 조건을 모두 만족하면 count하게 됩니다.</p>
<h2 id="멀티-해쉬"><strong>멀티 해쉬</strong></h2>
<p>PCY에서 pass1 단계에서 여러 개의 해시 테이블을 동시에 사용하는 것은 원래 한 개의 해시 테이블만 사용하는 것과는 달리 메모리 사용량을 줄일 수 있는 잠재적인 장점이 있습니다. 그러나 이러한 접근 방식은 리스크도 동반합니다. 해시 테이블이 두 개인 경우, 각 테이블이 담을 수 있는 메모리 크기가 절반으로 줄어들게 됩니다. 그 count들이 minimum support 넘긴다면 , 의미 가없어 더 이상 효과적인 방법이 아니게 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/fab50c59-7bdd-44b3-9d9d-33165cbe9b8a/image.png" alt=""></p>
<h1 id="random-sampling">Random sampling</h1>
<p>Market-Basket 데이터가 매우 큰 경우, 그 중 일부를 랜덤하게 샘플링하여 사용합니다. 예를 들어, 전체 바스켓의 10% 정보만을 랜덤하게 추출하는 것은 단 한 번의 데이터 읽기 과정만으로 이루어지므로 1-pass 알고리즘으로 간주됩니다.</p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/96c9e6f6-234b-4cd2-8ad8-ad415b0744ad/image.png" alt=""></p>
<p>첫 번째로는 바스켓을 위한 샘플들이 포함되고, 두 번째로는 카운트를 위한 메모리가 할당됩니다. 그러나 바스켓 샘플이 매우 작기 때문에 모든 것이 메모리에 쉽게 저장될 수 있습니다. 여기서 주의해야 할 점은 원래의 minimum support가 있었지만 이제 샘플링을 하였으므로, 샘플 크기에 맞게 minimum support를 조정해야 한다는 것입니다. 예를 들어, 전체 데이터에서는 20번 이상 나타나야 하는데, 1/4의 데이터만 사용한다면 5번 이상 나타나면 충분합니다.</p>
<p>그러나 이러한 Random sampling은 전체 데이터가 아닌 일부 데이터만 샘플링되었기 때문에 오류가 발생할 가능성이 있습니다. 이는 주요한 리스크 요인 중 하나입니다. </p>
<h1 id="random-sampling-의-단점-일부-데이터만-샘플링-했기-때문에-오류가-생기게-됩니다">Random sampling 의 단점 일부 데이터만 샘플링 했기 때문에 오류가 생기게 됩니다.</h1>
<h2 id="false-positive">False positive</h2>
<p>실제로는 빈발하지 않지만 빈발한 것처럼 나타나는 아이템을 발견한 후, 실제로 빈발한지를 확인하기 위해 한 번 더 패스를 실행하여 검증할 수 있습니다. 이를 통해 해당 아이템이 실제로 빈발한지 여부를 확인하고, 필요하다면 제거할 수 있습니다.</p>
<h2 id="false-negative">False negative</h2>
<p>실제로는 빈발한 아이템셋이지만 알고리즘 실행 결과에는 빈발하지 않은 것으로 나타나는 경우가 있습니다. 이는 False positive라고 합니다. False positive의 경우에는 오류를 제거할 수 없는데, 그 이유는 원래 아이템셋이 존재했지만 우연히 랜덤하게 샘플링된 아이템셋이 해당 빈발성을 충분히 포착하지 못할 수 있기 때문입니다.</p>
<p>False negative를 줄이기 위한 한 가지 좋은 방법은 minimum support를 줄이는 것입니다. Minimum support를 줄이면 조금만 나타나도 아이템셋이 빈발한 것처럼 보이기 때문에 오류를 줄일 수 있습니다. 그러나 이렇게 minimum support를 줄이면 frequent한 후보 아이템셋이 많아지므로 메모리 요구량이 늘어날 수 있습니다. 또한, 실제로는 빈발하지 않은데 빈발한 것으로 나타나는 False positive가 증가할 수 있습니다. 이러한 장단점을 고려하여 적절한 선택이 필요합니다.</p>
<h1 id="son-알고리즘">SON 알고리즘</h1>
<p>현재 전체 데이터가 매우 크기 때문에 문제가 발생합니다. 이를 해결하기 위해 전체 데이터를 k개의 chunk로 나누는 방법을 사용할 수 있습니다. 예를 들어, k가 10이라면 전체 데이터를 10개의 조각으로 나눈 후 각각의 조각을 메인 메모리로 읽습니다. 각각의 조각은 메모리에 쉽게 들어갈 정도로 작다고 가정합니다. 그런 다음 메모리에 올려진 각각의 조각에서 알고리즘을 실행하여 모든 frequent itemset을 찾습니다.</p>
<p><img src="https://velog.velcdn.com/images/youjininny__/post/ab4c0cf9-2664-4b5c-9861-fd5d41c69699/image.png" alt=""></p>
<p>원래의 minimum support가 s였다면 이를 k개의 chunk로 나눈 경우에는 minimum support를 k분의 s로 줄여주어야 합니다. 각각의 chunk에서 candidate를 찾은 다음에 한 번 더 pass를 돌려서 전체 바스켓에서 실제로 frequent한 candidate를 확인합니다. 이때, 모든 chunk에서 빈발하지 않았다면 전체적으로 support가 s보다 작아지게 됩니다. 각각의 chunk에서 candidate를 찾은 다음에 한 번 더 pass를 돌려서 전체 바스켓에서 실제로 frequent한 itemset을 찾는 것입니다. 따라서 앞에서 설명한 monotonicity 개념이 여기서 나오게 됩니다. 목표는 전체 n개의 바스켓에서 최소 s번 이상 나온 itemset을 찾는 것인데, 이 n개의 바스켓을 k개의 chunk로 나누었기 때문에 이를 고려하여 minimum support를 조정하고, 각각의 chunk에서 frequent한 candidate를 찾은 다음 전체 바스켓에서 실제로 frequent한 itemset을 찾아내는 것입니다.</p>
<h1 id="이글을-마치며">이글을 마치며</h1>
<p>지금까지 Market Basket Analysis에 대한 알고리즘 및 메모리 구성에 대해 살펴보았습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데이터 마이닝] frequent itemset Market-Basket-Model(1)]]></title>
            <link>https://velog.io/@youjininny__/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EC%B2%98%EB%A6%ACfrequent-itemset-Apriori-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%981</link>
            <guid>https://velog.io/@youjininny__/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EC%B2%98%EB%A6%ACfrequent-itemset-Apriori-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%981</guid>
            <pubDate>Fri, 19 Apr 2024 10:21:04 GMT</pubDate>
            <description><![CDATA[<h1 id="marketbasket-model-장바구니-연관-규칙">Market‑Basket Model (장바구니 연관 규칙)</h1>
<p>어떤 고객이 특정 상품을 살 때, 함께 자주 구매되는 다른 상품이 존재하며,<br>이를 찾아내는 것이 <strong>Market‑Basket Model</strong>의 핵심입니다.</p>
<p>예시:  </p>
<blockquote>
<p>“우유를 사는 고객들은 치즈도 함께 사는 경향이 있음”</p>
</blockquote>
<hr>
<h2 id="1-기본-개념-정리">1. 기본 개념 정리</h2>
<h3 id="support-지지도">Support (지지도)</h3>
<p>Support는 특정 <strong>아이템 집합(Itemset)</strong>이 전체 거래 데이터에서 얼마나 자주 나타나는지를 의미합니다.<br>→ <strong>비율(%)</strong> 혹은 <strong>횟수</strong>로 표현되며, 분석 목적에 따라 기준은 달라질 수 있습니다.</p>
<h3 id="confidence-신뢰도">Confidence (신뢰도)</h3>
<blockquote>
<p><code>conf(i → j) = support(i ∧ j) / support(i)</code></p>
</blockquote>
<ul>
<li>i를 포함하는 거래 중에서, j도 함께 포함된 거래 비율  </li>
<li>값이 클수록 &quot;<strong>i를 구매한 고객이 j도 함께 구매할 확률</strong>&quot;이 높다는 뜻입니다.</li>
</ul>
<hr>
<h2 id="2-confidence만으로는-충분하지-않다-interest의-필요성">2. Confidence만으로는 충분하지 않다: Interest의 필요성</h2>
<h3 id="문제점">문제점</h3>
<ul>
<li>어떤 아이템 x를 사면 milk를 산다는 규칙: <code>x → milk</code></li>
<li>milk 자체가 자주 구매되기 때문에, 어떤 x든 conf는 높게 나올 수 있음</li>
<li>하지만 이는 <strong>진짜 연관성</strong>이 아닐 수 있음</li>
</ul>
<h3 id="interest의-정의">Interest의 정의</h3>
<blockquote>
<p><code>interest(i → j) = conf(i → j) – support(j)</code></p>
</blockquote>
<ul>
<li>j의 기본 구매율을 빼면, 진정한 연관성 여부를 파악 가능  </li>
<li><strong>j의 구매율이 낮지만 conf가 높다면</strong> → <strong>높은 interest → 마케팅 인사이트</strong></li>
</ul>
<hr>
<h2 id="3-연관-규칙-예시-j-→-m-분석">3. 연관 규칙 예시: <code>j → m</code> 분석</h2>
<h3 id="트랜잭션-데이터">트랜잭션 데이터</h3>
<ul>
<li>전체 거래: B1, B2, B3, B4, B5, B6 → <strong>6건</strong></li>
<li><code>j</code>가 포함된 거래: B1, B2, B4, B5, B6 → <strong>5건</strong></li>
<li><code>j</code>와 <code>m</code>이 모두 포함된 거래: B1, B2, B5 → <strong>3건</strong></li>
</ul>
<h3 id="계산">계산</h3>
<p>conf(j → m) = 3 / 5 = 0.6
support(m) = 3 / 6 = 0.5
interest = 0.6 – 0.5 = 0.1</p>
<p>→ <strong>interest = 0.1</strong><br>→ 단순한 우연이 아니라 <strong>상대적으로 유의미한 연관 규칙</strong></p>
<hr>
<h2 id="4-frequent-itemset-종류">4. Frequent Itemset 종류</h2>
<h3 id="maximal-frequent-itemset">Maximal Frequent Itemset</h3>
<ul>
<li>더 이상 빈발한 <strong>superset(상위 집합)</strong>이 존재하지 않는 itemset</li>
<li>예:  <ul>
<li>{A}, {A,B}는 {A,B,D}라는 superset이 있기 때문에 <strong>Maximal 아님</strong></li>
<li>{B,C}는 확장 불가 → <strong>Maximal</strong></li>
</ul>
</li>
</ul>
<h3 id="closed-frequent-itemset">Closed Frequent Itemset</h3>
<ul>
<li>같은 support 값을 가진 빈발 superset이 <strong>존재하지 않는</strong> itemset</li>
<li>예:  <ul>
<li>{A,B,C}가 support 3을 가지고 있고, {A}는 support가 낮다면<br>→ {A,B,C}는 <strong>Closed</strong>  </li>
<li>{B}는 더 큰 Closed frequent itemset에 포함되면 <strong>제외</strong></li>
</ul>
</li>
</ul>
<hr>
<h2 id="5-연관-규칙-발견-절차-association-rule-mining">5. 연관 규칙 발견 절차 (Association Rule Mining)</h2>
<h3 id="step-1-frequent-itemset-탐색">Step 1: Frequent Itemset 탐색</h3>
<ul>
<li>최소 support 기준을 만족하는 itemset 먼저 추출</li>
</ul>
<h3 id="step-2-연관-규칙-생성">Step 2: 연관 규칙 생성</h3>
<ul>
<li><code>i → j</code> 관계에 대해 아래 항목 계산:<ul>
<li><code>conf(i → j)</code></li>
<li><code>interest(i → j)</code></li>
</ul>
</li>
</ul>
<h3 id="step-3-유의미한-규칙-필터링">Step 3: 유의미한 규칙 필터링</h3>
<ul>
<li><strong>높은 confidence + 높은 interest</strong> 조합이<br>→ 마케팅적으로 가장 활용 가치 높은 규칙</li>
</ul>
<hr>
<h2 id="요약-연관-규칙-분석의-핵심">요약: 연관 규칙 분석의 핵심</h2>
<ul>
<li><strong>Support</strong>: 얼마나 자주 등장하는가?</li>
<li><strong>Confidence</strong>: 함께 등장할 확률은 얼마나 되는가?</li>
<li><strong>Interest</strong>: 진짜 연관성인가, 아니면 단순 인기 아이템인가?</li>
</ul>
<blockquote>
<p>✔️ <strong>Confidence와 Interest를 함께 고려</strong>하면<br>→ 실제로 유의미한 상품 연관 규칙을 발굴할 수 있으며,<br>→ 마케팅, 추천 시스템, 재고 운영 등에 효과적으로 활용 가능합니다.</p>
</blockquote>
<p>-이 블로그 내용은 서울대학교 인공지능 학과 청강 데이터마이닝 수업을 기반으로 작성한 블로그 입니다-</p>
]]></description>
        </item>
    </channel>
</rss>