<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>khu2172 님의 블로그</title>
    <link>https://khu2172.tistory.com/</link>
    <description>khu2172 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Sat, 18 Jul 2026 15:36:50 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>khu2172</managingEditor>
    <item>
      <title>CORS란? (Cross-Origin Resource Sharing)</title>
      <link>https://khu2172.tistory.com/87</link>
      <description>&lt;h2 data-end=&quot;110&quot; data-start=&quot;99&quot; data-ke-size=&quot;size26&quot;&gt;CORS란?&lt;/h2&gt;
&lt;p data-end=&quot;203&quot; data-start=&quot;112&quot; data-ke-size=&quot;size16&quot;&gt;CORS(Cross-Origin Resource Sharing)는&lt;br /&gt;&lt;b&gt;서로 다른 Origin 간의 리소스 공유를 허용하는 표준 보안 우회 기술&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;기본적으로 웹 브라우저는 보안상의 이유로 다른 출처(origin)의 리소스 요청을 차단한다.&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;CORS는 이러한 &lt;b&gt;제약을 우회하여 다른 출처의 리소스에 접근할 수 있게&lt;/b&gt; 해준다.&lt;/p&gt;
&lt;hr data-end=&quot;318&quot; data-start=&quot;315&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;350&quot; data-start=&quot;320&quot; data-ke-size=&quot;size26&quot;&gt;Same-Origin Policy(SOP)란?&lt;/h2&gt;
&lt;p data-end=&quot;425&quot; data-start=&quot;352&quot; data-ke-size=&quot;size16&quot;&gt;브라우저가 기본적으로 따르는 보안 정책이다.&lt;br /&gt;&amp;rarr; 동일한 출처(origin)에서만 리소스를 공유할 수 있도록 제한한다.&lt;/p&gt;
&lt;h3 data-end=&quot;443&quot; data-start=&quot;427&quot; data-ke-size=&quot;size23&quot;&gt;Origin이란?&lt;/h3&gt;
&lt;p data-end=&quot;472&quot; data-start=&quot;444&quot; data-ke-size=&quot;size16&quot;&gt;Origin은 다음 세 가지의 조합으로 구성된다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;561&quot; data-start=&quot;474&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;497&quot; data-start=&quot;474&quot;&gt;&lt;b&gt;프로토콜&lt;/b&gt;: http, https&lt;/li&gt;
&lt;li data-end=&quot;531&quot; data-start=&quot;498&quot;&gt;&lt;b&gt;호스트&lt;/b&gt;: localhost, naver.com 등&lt;/li&gt;
&lt;li data-end=&quot;561&quot; data-start=&quot;532&quot;&gt;&lt;b&gt;포트 번호&lt;/b&gt;: 80, 8080, 3000 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;611&quot; data-start=&quot;563&quot; data-ke-size=&quot;size16&quot;&gt;이 중 &lt;b&gt;하나라도 다르면 다른 Origin으로 판단&lt;/b&gt;되어 SOP에 의해 차단된다.&lt;/p&gt;
&lt;hr data-end=&quot;616&quot; data-start=&quot;613&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;650&quot; data-start=&quot;618&quot; data-ke-size=&quot;size26&quot;&gt;Preflight Request(프리플라잇 요청)&lt;/h2&gt;
&lt;p data-end=&quot;821&quot; data-start=&quot;652&quot; data-ke-size=&quot;size16&quot;&gt;CORS 요청 중에서도 GET, POST 외의 HTTP 메서드(PUT, DELETE 등)를 사용하거나,&lt;br /&gt;&lt;b&gt;커스텀 헤더&lt;/b&gt;가 포함된 요청의 경우 브라우저는 본 요청을 보내기 전에 사전 확인용 요청(OPTIONS)을 보낸다. 이를 &lt;b&gt;Preflight 요청&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;h3 data-end=&quot;836&quot; data-start=&quot;823&quot; data-ke-size=&quot;size23&quot;&gt;동작 흐름:&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;937&quot; data-start=&quot;837&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;873&quot; data-start=&quot;837&quot;&gt;브라우저가 서버에 OPTIONS 메서드로 사전 요청 전송&lt;/li&gt;
&lt;li data-end=&quot;912&quot; data-start=&quot;874&quot;&gt;서버가 해당 요청을 허용하면, 브라우저가 본 요청을 실제로 보냄&lt;/li&gt;
&lt;li data-end=&quot;937&quot; data-start=&quot;913&quot;&gt;허용되지 않으면 브라우저가 요청을 차단&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;942&quot; data-start=&quot;939&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;981&quot; data-start=&quot;944&quot; data-ke-size=&quot;size26&quot;&gt;CORS 에러 해결 경험 (Spring Boot 프로젝트)&lt;/h2&gt;
&lt;p data-end=&quot;1073&quot; data-start=&quot;983&quot; data-ke-size=&quot;size16&quot;&gt;실제 프로젝트 개발 중, 프론트엔드(React)와 백엔드(Spring Boot)가&lt;br /&gt;&lt;b&gt;서로 다른 포트에서 실행되며 CORS 에러가 발생한 경험&lt;/b&gt;이 있다.&lt;/p&gt;
&lt;p data-end=&quot;1089&quot; data-start=&quot;1075&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1089&quot; data-start=&quot;1075&quot; data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하기 위해,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1171&quot; data-start=&quot;1090&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1112&quot; data-start=&quot;1090&quot;&gt;Spring의 설정 클래스를 만들고,&lt;/li&gt;
&lt;li data-end=&quot;1138&quot; data-start=&quot;1113&quot;&gt;특정 Origin을 허용하도록 설정한 뒤,&lt;/li&gt;
&lt;li data-end=&quot;1171&quot; data-start=&quot;1139&quot;&gt;프리플라잇 요청이 정상적으로 응답되도록 처리하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1217&quot; data-start=&quot;1173&quot; data-ke-size=&quot;size16&quot;&gt;이후 브라우저에서 더 이상 차단되지 않고 정상적인 API 요청이 가능해졌다.&lt;/p&gt;
&lt;hr data-end=&quot;1222&quot; data-start=&quot;1219&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1231&quot; data-start=&quot;1224&quot; data-ke-size=&quot;size26&quot;&gt;요약&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1514&quot; data-start=&quot;1233&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1327&quot; data-start=&quot;1281&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1298&quot; data-start=&quot;1281&quot;&gt;CORS&lt;/td&gt;
&lt;td data-end=&quot;1327&quot; data-start=&quot;1298&quot; data-col-size=&quot;sm&quot;&gt;다른 출처 간 리소스 공유를 허용하는 웹 표준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1366&quot; data-start=&quot;1328&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1345&quot; data-start=&quot;1328&quot;&gt;SOP&lt;/td&gt;
&lt;td data-end=&quot;1366&quot; data-start=&quot;1345&quot; data-col-size=&quot;sm&quot;&gt;브라우저의 동일 출처 보안 정책&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1413&quot; data-start=&quot;1367&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1384&quot; data-start=&quot;1367&quot;&gt;Origin&lt;/td&gt;
&lt;td data-end=&quot;1413&quot; data-start=&quot;1384&quot; data-col-size=&quot;sm&quot;&gt;Protocol + Host + Port 조합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1465&quot; data-start=&quot;1414&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1431&quot; data-start=&quot;1414&quot;&gt;Preflight&lt;/td&gt;
&lt;td data-end=&quot;1465&quot; data-start=&quot;1431&quot; data-col-size=&quot;sm&quot;&gt;본 요청 전 OPTIONS 요청을 통해 허용 여부 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1514&quot; data-start=&quot;1466&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1477&quot; data-start=&quot;1466&quot;&gt;해결 경험&lt;/td&gt;
&lt;td data-end=&quot;1514&quot; data-start=&quot;1477&quot; data-col-size=&quot;sm&quot;&gt;백엔드에서 특정 Origin을 허용해 브라우저 차단을 해소함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1519&quot; data-start=&quot;1516&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1530&quot; data-start=&quot;1521&quot; data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-end=&quot;1636&quot; data-start=&quot;1532&quot; data-ke-size=&quot;size16&quot;&gt;CORS는 단순한 에러처럼 보일 수 있지만,&lt;br /&gt;&lt;b&gt;웹 보안을 위한 핵심 메커니즘&lt;/b&gt;이며, 프론트와 백엔드가 분리된 환경에선&lt;br /&gt;&lt;b&gt;반드시 이해하고 설정할 수 있어야 하는 개념&lt;/b&gt;이다.&lt;/p&gt;</description>
      <category>Backend/Java &amp;amp; Spring</category>
      <author>khu2172</author>
      <guid isPermaLink="true">https://khu2172.tistory.com/87</guid>
      <comments>https://khu2172.tistory.com/87#entry87comment</comments>
      <pubDate>Thu, 7 Aug 2025 17:59:08 +0900</pubDate>
    </item>
    <item>
      <title>JWT와 OAuth의 차이점 정리</title>
      <link>https://khu2172.tistory.com/86</link>
      <description>&lt;h3 data-end=&quot;139&quot; data-start=&quot;112&quot; data-ke-size=&quot;size23&quot;&gt;1. JWT (JSON Web Token)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;352&quot; data-start=&quot;140&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;188&quot; data-start=&quot;140&quot;&gt;JWT는 &lt;b&gt;토큰의 한 종류&lt;/b&gt;로, 인증 및 권한 부여 정보를 담는 데 사용된다.&lt;/li&gt;
&lt;li data-end=&quot;239&quot; data-start=&quot;189&quot;&gt;&lt;b&gt;토큰 자체에 명확한 정보&lt;/b&gt;(사용자 ID, 권한, 만료 시간 등)가 들어 있다.&lt;/li&gt;
&lt;li data-end=&quot;283&quot; data-start=&quot;240&quot;&gt;별도의 저장소에 토큰의 상태를 저장하지 않고 토큰만으로 정보를 검증한다.&lt;/li&gt;
&lt;li data-end=&quot;352&quot; data-start=&quot;284&quot;&gt;구성: Header.Payload.Signature 형식으로 구성되며 Base64Url로 인코딩된 정보를 담는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;362&quot; data-start=&quot;354&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;487&quot; data-start=&quot;363&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;428&quot; data-start=&quot;363&quot;&gt;&lt;b&gt;자체 완결성(Self-contained)&lt;/b&gt;: 토큰만으로도 사용자의 인증 및 권한 정보를 확인할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;487&quot; data-start=&quot;429&quot;&gt;&lt;b&gt;상태 비저장(Stateless)&lt;/b&gt;: 서버가 상태 정보를 저장할 필요가 없어 확장성이 뛰어나다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;522&quot; data-start=&quot;489&quot; data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;2. OAuth (Open Authorization)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;775&quot; data-start=&quot;523&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;583&quot; data-start=&quot;523&quot;&gt;OAuth는 토큰이 아니라, 토큰을 얻기 위한&lt;b&gt;인증 및 권한 부여 절차를 정의한 프레임워크&lt;/b&gt;이다.&lt;/li&gt;
&lt;li data-end=&quot;643&quot; data-start=&quot;584&quot;&gt;애플리케이션이 사용자를 대신하여 보호된 리소스에 접근할 수 있도록 권한을 위임하는 표준 프로토콜이다.&lt;/li&gt;
&lt;li data-end=&quot;713&quot; data-start=&quot;644&quot;&gt;OAuth 프레임워크를 통해 발급된 &lt;b&gt;OAuth Bearer Token&lt;/b&gt;은 &lt;b&gt;랜덤한 문자열&lt;/b&gt;로 구성되어 있다.&lt;/li&gt;
&lt;li data-end=&quot;775&quot; data-start=&quot;714&quot;&gt;토큰 자체에는 사용자의 민감한 정보가 직접 포함되지 않고, 토큰을 통해 리소스 서버에서 정보를 조회한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;785&quot; data-start=&quot;777&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;976&quot; data-start=&quot;786&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;864&quot; data-start=&quot;786&quot;&gt;&lt;b&gt;권한 위임&lt;/b&gt;: 사용자의 자격 증명(비밀번호)을 공유하지 않고도 애플리케이션이 제한된 권한으로 사용자의 데이터에 접근할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;976&quot; data-start=&quot;865&quot;&gt;&lt;b&gt;다양한 시나리오 지원&lt;/b&gt;: 권한 부여 유형(Authorization Code, Implicit, Password, Client Credentials 등)을 통해 다양한 사용 사례를 지원한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;985&quot; data-start=&quot;978&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-end=&quot;985&quot; data-start=&quot;978&quot; data-ke-size=&quot;size23&quot;&gt;비교표&lt;/h3&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1200&quot; data-start=&quot;986&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;JWT&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;OAuth&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1046&quot; data-start=&quot;1015&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1018&quot; data-start=&quot;1015&quot;&gt;종류&lt;/td&gt;
&lt;td data-end=&quot;1028&quot; data-start=&quot;1018&quot; data-col-size=&quot;sm&quot;&gt;토큰(token)&lt;/td&gt;
&lt;td data-end=&quot;1046&quot; data-start=&quot;1028&quot; data-col-size=&quot;sm&quot;&gt;프레임워크(framework)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1081&quot; data-start=&quot;1047&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1053&quot; data-start=&quot;1047&quot;&gt;정보 포함&lt;/td&gt;
&lt;td data-end=&quot;1063&quot; data-start=&quot;1053&quot; data-col-size=&quot;sm&quot;&gt;명확한 정보 포함&lt;/td&gt;
&lt;td data-end=&quot;1081&quot; data-start=&quot;1063&quot; data-col-size=&quot;sm&quot;&gt;랜덤한 문자열 (정보 미포함)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1119&quot; data-start=&quot;1082&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1088&quot; data-start=&quot;1082&quot;&gt;상태 관리&lt;/td&gt;
&lt;td data-end=&quot;1106&quot; data-start=&quot;1088&quot; data-col-size=&quot;sm&quot;&gt;상태 비저장(Stateless)&lt;/td&gt;
&lt;td data-end=&quot;1119&quot; data-start=&quot;1106&quot; data-col-size=&quot;sm&quot;&gt;토큰 상태 관리 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1152&quot; data-start=&quot;1120&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1123&quot; data-start=&quot;1120&quot;&gt;목적&lt;/td&gt;
&lt;td data-end=&quot;1137&quot; data-start=&quot;1123&quot; data-col-size=&quot;sm&quot;&gt;인증 및 권한 정보 전달&lt;/td&gt;
&lt;td data-end=&quot;1152&quot; data-start=&quot;1137&quot; data-col-size=&quot;sm&quot;&gt;애플리케이션의 권한 위임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1200&quot; data-start=&quot;1153&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1159&quot; data-start=&quot;1153&quot;&gt;사용 예시&lt;/td&gt;
&lt;td data-end=&quot;1177&quot; data-start=&quot;1159&quot; data-col-size=&quot;sm&quot;&gt;로그인 세션 관리, API 접근&lt;/td&gt;
&lt;td data-end=&quot;1200&quot; data-start=&quot;1177&quot; data-col-size=&quot;sm&quot;&gt;SNS 연동 로그인, 써드파티 앱 접근&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1210&quot; data-start=&quot;1202&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1342&quot; data-start=&quot;1211&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1256&quot; data-start=&quot;1211&quot;&gt;JWT는 명확한 사용자 정보를 담아 인증과 권한 관리를 위한 토큰 형식이다.&lt;/li&gt;
&lt;li data-end=&quot;1342&quot; data-start=&quot;1257&quot;&gt;OAuth는 외부 애플리케이션에 권한을 위임하는 프로세스를 표준화한 프레임워크로, OAuth가 발급하는 토큰 자체는 정보를 담지 않은 랜덤 값이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1396&quot; data-start=&quot;1344&quot; data-ke-size=&quot;size16&quot;&gt;이러한 특성을 잘 이해하면 보다 안전하고 효율적인 인증 및 인가 시스템을 설계할 수 있다.&lt;/p&gt;</description>
      <category>Backend/Java &amp;amp; Spring</category>
      <author>khu2172</author>
      <guid isPermaLink="true">https://khu2172.tistory.com/86</guid>
      <comments>https://khu2172.tistory.com/86#entry86comment</comments>
      <pubDate>Tue, 29 Jul 2025 00:54:34 +0900</pubDate>
    </item>
    <item>
      <title>[트러블슈팅] PasswordEncoder 등 빈 주입 오류, 컴포넌트 스캔 누락</title>
      <link>https://khu2172.tistory.com/85</link>
      <description>&lt;h3 data-end=&quot;161&quot; data-start=&quot;148&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 상황&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;429&quot; data-start=&quot;163&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;293&quot; data-start=&quot;163&quot;&gt;Parameter 1 of constructor ... required a bean of type 'PasswordEncoder' that could not be found&lt;br /&gt;(서비스 생성자 파라미터에서 주입 오류 발생)&lt;/li&gt;
&lt;li data-end=&quot;429&quot; data-start=&quot;294&quot;&gt;AppConfig에서 @Bean으로 PasswordEncoder를 정상 등록했음에도&lt;br /&gt;&lt;b&gt;Could not autowire. No beans of 'PasswordEncoder' type found.&lt;/b&gt;&lt;br /&gt;라는 에러가 계속 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;434&quot; data-start=&quot;431&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;449&quot; data-start=&quot;436&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;원인 분석&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;741&quot; data-start=&quot;451&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;517&quot; data-start=&quot;451&quot;&gt;AppConfig(설정 클래스)를&lt;br /&gt;com.example.config(=최상위) 패키지에 두었으나,&lt;/li&gt;
&lt;li data-end=&quot;680&quot; data-start=&quot;518&quot;&gt;&lt;b&gt;메인 클래스(@SpringBootApplication)가 com.example.board 하위에 위치&lt;/b&gt;&lt;br /&gt;&amp;rarr; Spring Boot의 기본 컴포넌트 스캔 정책상&lt;br /&gt;메인 클래스 &amp;ldquo;하위&amp;rdquo; 패키지만 스캔&lt;br /&gt;&amp;rarr; 최상위 config 패키지가 &lt;b&gt;스캔 대상에서 누락됨&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;741&quot; data-start=&quot;681&quot;&gt;이로 인해 PasswordEncoder 빈(@Bean)이 등록되지 않아&lt;br /&gt;서비스에서 주입 오류 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;746&quot; data-start=&quot;743&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;761&quot; data-start=&quot;748&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;해결 방법&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1157&quot; data-start=&quot;763&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;942&quot; data-start=&quot;763&quot;&gt;&lt;b&gt;메인 클래스를 &amp;ldquo;최상위 패키지(com.example)&amp;rdquo;로 이동&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;942&quot; data-start=&quot;810&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;897&quot; data-start=&quot;810&quot;&gt;BoardApplication을 com.example에 두면&lt;br /&gt;그 하위 전체(=config, board, user ...)가 스캔됨&lt;/li&gt;
&lt;li data-end=&quot;942&quot; data-start=&quot;901&quot;&gt;모든 빈(@Bean, @Service, @Mapper 등)이 자동 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1039&quot; data-start=&quot;944&quot;&gt;또는,&lt;br /&gt;&lt;b&gt;AppConfig를 메인 클래스 하위 패키지(com.example.board.config)로 옮기기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1039&quot; data-start=&quot;1023&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1039&quot; data-start=&quot;1023&quot;&gt;하위에 두면 무조건 스캔됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1157&quot; data-start=&quot;1041&quot;&gt;&lt;b&gt;대안:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1157&quot; data-start=&quot;1057&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1121&quot; data-start=&quot;1057&quot;&gt;@ComponentScan(basePackages = &quot;com.example&quot;)로 스캔 범위 명시적으로 확장&lt;/li&gt;
&lt;li data-end=&quot;1157&quot; data-start=&quot;1125&quot;&gt;(실무에서는 메인 클래스를 상위로 두는 게 더 보편적)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;1162&quot; data-start=&quot;1159&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1179&quot; data-start=&quot;1164&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결과 및 교훈&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1388&quot; data-start=&quot;1181&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1247&quot; data-start=&quot;1181&quot;&gt;메인 클래스를 &amp;ldquo;최상위 패키지&amp;rdquo;에 두었더니&lt;br /&gt;PasswordEncoder 등 모든 빈 주입 문제가 바로 해결!&lt;/li&gt;
&lt;li data-end=&quot;1363&quot; data-start=&quot;1248&quot;&gt;&lt;b&gt;Spring Boot의 컴포넌트 스캔 기본 정책은&lt;br /&gt;&amp;ldquo;메인 클래스와 그 하위 패키지&amp;rdquo;만 스캔&lt;/b&gt;&lt;br /&gt;&amp;rarr; 최상위 config, 공통 유틸 등은 항상 &amp;ldquo;메인 클래스보다 하위/동일 위치&amp;rdquo;에 둘 것&lt;/li&gt;
&lt;li data-end=&quot;1388&quot; data-start=&quot;1364&quot;&gt;또는, 스캔 범위를 명시적으로 확장할 것&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1590&quot; data-start=&quot;1587&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;1604&quot; data-start=&quot;1592&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈 주입 오류, 컴포넌트 스캔 범위 체크가 최우선!&lt;br /&gt;스프링 구조 설계 시 &amp;ldquo;메인 클래스, 설정 클래스의 위치&amp;rdquo;에 항상 주의하자!&lt;/p&gt;</description>
      <category>Archive/예전 TIL</category>
      <author>khu2172</author>
      <guid isPermaLink="true">https://khu2172.tistory.com/85</guid>
      <comments>https://khu2172.tistory.com/85#entry85comment</comments>
      <pubDate>Wed, 23 Jul 2025 00:54:30 +0900</pubDate>
    </item>
    <item>
      <title>IoC와 IoC 컨테이너란?(스프링에서의 역할 정리)</title>
      <link>https://khu2172.tistory.com/84</link>
      <description>&lt;h2 data-end=&quot;163&quot; data-start=&quot;130&quot; data-ke-size=&quot;size26&quot;&gt;1. IoC(Inversion of Control)란?&lt;/h2&gt;
&lt;p data-end=&quot;307&quot; data-start=&quot;165&quot; data-ke-size=&quot;size16&quot;&gt;IoC(제어의 역전)는 객체의 생성과 생명주기 관리, 의존성 주입 등 프로그램의 제어권을 개발자가 아닌 외부(주로 프레임워크나 컨테이너)에 맡기는 설계 원칙입니다.&lt;br /&gt;이 덕분에 개발자는 객체 관리에서 벗어나 비즈니스 로직 구현에 집중할 수 있게 됩니다.&lt;/p&gt;
&lt;hr data-end=&quot;312&quot; data-start=&quot;309&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;330&quot; data-start=&quot;314&quot; data-ke-size=&quot;size26&quot;&gt;2. IoC 컨테이너란?&lt;/h2&gt;
&lt;p data-end=&quot;502&quot; data-start=&quot;332&quot; data-ke-size=&quot;size16&quot;&gt;IoC 컨테이너는 IoC 원칙을 실제로 구현하는 &lt;b&gt;객체 관리자&lt;/b&gt;입니다.&lt;br /&gt;스프링 프레임워크에서는 IoC 컨테이너가 애플리케이션을 구성하는 Bean(객체)들을 생성하고, 서로 연결하며, 필요할 때 소멸까지 관리합니다.&lt;br /&gt;대표적으로 ApplicationContext, BeanFactory가 있습니다.&lt;/p&gt;
&lt;hr data-end=&quot;507&quot; data-start=&quot;504&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;534&quot; data-start=&quot;509&quot; data-ke-size=&quot;size26&quot;&gt;3. 스프링 IoC 컨테이너의 주요 역할&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;926&quot; data-start=&quot;536&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;608&quot; data-start=&quot;536&quot;&gt;&lt;b&gt;객체(Bean) 생성&lt;/b&gt;&lt;br /&gt;개발자가 직접 new로 객체를 만들지 않고, 컨테이너가 빈 설정에 따라 객체를 생성합니다.&lt;/li&gt;
&lt;li data-end=&quot;663&quot; data-start=&quot;610&quot;&gt;&lt;b&gt;객체의 생명주기 관리&lt;/b&gt;&lt;br /&gt;객체의 생성부터 소멸까지 전체 라이프사이클을 책임집니다.&lt;/li&gt;
&lt;li data-end=&quot;776&quot; data-start=&quot;665&quot;&gt;&lt;b&gt;의존관계 주입(Dependency Injection, DI)&lt;/b&gt;&lt;br /&gt;객체가 필요로 하는 다른 객체를 자동으로 연결해줍니다.&lt;br /&gt;덕분에 객체 간 결합도가 낮아지고 코드가 더 유연해집니다.&lt;/li&gt;
&lt;li data-end=&quot;836&quot; data-start=&quot;778&quot;&gt;&lt;b&gt;설정 및 환경 관리&lt;/b&gt;&lt;br /&gt;빈의 프로퍼티, 환경 설정, 프로파일 등 각종 설정값을 관리합니다.&lt;/li&gt;
&lt;li data-end=&quot;926&quot; data-start=&quot;838&quot;&gt;&lt;b&gt;AOP 등 부가기능 적용&lt;/b&gt;&lt;br /&gt;트랜잭션 처리, AOP(관점 지향 프로그래밍) 같은 기능도 IoC 컨테이너가 객체에 자동으로 적용해줄 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;931&quot; data-start=&quot;928&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;951&quot; data-start=&quot;933&quot; data-ke-size=&quot;size26&quot;&gt;4. IoC 컨테이너의 장점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1030&quot; data-start=&quot;953&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;977&quot; data-start=&quot;953&quot;&gt;&lt;b&gt;코드 결합도 감소 및 유연성 향상&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;994&quot; data-start=&quot;978&quot;&gt;&lt;b&gt;테스트 용이성 증가&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1015&quot; data-start=&quot;995&quot;&gt;&lt;b&gt;확장성 및 유지보수성 개선&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1030&quot; data-start=&quot;1016&quot;&gt;&lt;b&gt;중복 코드 감소&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1035&quot; data-start=&quot;1032&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1045&quot; data-start=&quot;1037&quot; data-ke-size=&quot;size26&quot;&gt;5. 결론&lt;/h2&gt;
&lt;p data-end=&quot;1207&quot; data-start=&quot;1047&quot; data-ke-size=&quot;size16&quot;&gt;정리하자면,&lt;br /&gt;&lt;b&gt;스프링 IoC 컨테이너&lt;/b&gt;는 객체의 생성, 관리, 의존성 주입, 설정, 생명주기 관리 등 애플리케이션에서 필요한 핵심 작업을 자동으로 처리해주는 관리자입니다.&lt;br /&gt;이 덕분에 개발자는 비즈니스 로직 구현에 집중할 수 있고, 코드의 확장성과 유지보수성이 크게 향상됩니다.&lt;/p&gt;</description>
      <author>khu2172</author>
      <guid isPermaLink="true">https://khu2172.tistory.com/84</guid>
      <comments>https://khu2172.tistory.com/84#entry84comment</comments>
      <pubDate>Mon, 14 Jul 2025 23:59:46 +0900</pubDate>
    </item>
    <item>
      <title>[트러블슈팅] Spring 단위 테스트 실패</title>
      <link>https://khu2172.tistory.com/83</link>
      <description>&lt;h2 data-end=&quot;85&quot; data-start=&quot;54&quot; data-ke-size=&quot;size26&quot;&gt;1. &lt;b&gt;문제 상황&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;277&quot; data-start=&quot;109&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;224&quot; data-start=&quot;109&quot;&gt;회원(유저) 서비스의 단위 테스트 코드가&lt;br /&gt;&lt;b&gt;NullPointerException&lt;/b&gt;이나&lt;br /&gt;&lt;b&gt;IllegalStateException(&quot;id를 찾지 못함&quot;)&lt;/b&gt; 등&lt;br /&gt;각종 에러로 실패.&lt;/li&gt;
&lt;li data-end=&quot;277&quot; data-start=&quot;226&quot;&gt;테스트 흐름:&lt;br /&gt;회원가입 &amp;rarr; 전체 유저 목록에서 id 찾기 &amp;rarr; 단건 조회/삭제 검증&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;282&quot; data-start=&quot;279&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;303&quot; data-start=&quot;284&quot; data-ke-size=&quot;size26&quot;&gt;2. &lt;b&gt;증상/에러 메시지&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;422&quot; data-start=&quot;305&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;324&quot; data-start=&quot;305&quot;&gt;&lt;b&gt;가입 후 전체 유저: 0&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;342&quot; data-start=&quot;325&quot;&gt;&lt;b&gt;찾은 id: null&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;365&quot; data-start=&quot;343&quot;&gt;id를 찾지 못함 예외&lt;/li&gt;
&lt;li data-end=&quot;422&quot; data-start=&quot;366&quot;&gt;NullPointerException: ... because &quot;user&quot; is null&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;427&quot; data-start=&quot;424&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;444&quot; data-start=&quot;429&quot; data-ke-size=&quot;size26&quot;&gt;3. &lt;b&gt;원인 분석&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;685&quot; data-start=&quot;446&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;561&quot; data-start=&quot;446&quot;&gt;&lt;b&gt;Mock 환경에선 실제 DB 저장/조회가 발생하지 않음.&lt;/b&gt;&lt;br /&gt;&amp;rarr; 단순히 메소드 호출만 검증하는 구조라&lt;br /&gt;가짜 데이터의 반환값을 직접 세팅하지 않으면&lt;br /&gt;항상 빈 값(0개)만 반환.&lt;/li&gt;
&lt;li data-end=&quot;623&quot; data-start=&quot;563&quot;&gt;&lt;b&gt;테스트 코드에서 반환값 세팅을 생략해서,&lt;/b&gt;&lt;br /&gt;전체 유저 목록이 항상 0명 &amp;rarr; id 찾지 못함.&lt;/li&gt;
&lt;li data-end=&quot;685&quot; data-start=&quot;625&quot;&gt;&lt;b&gt;엔터티 클래스에 테스트용 생성자(id 포함) 누락&lt;/b&gt;&lt;br /&gt;&amp;rarr; 원하는 테스트 데이터를 만들지 못함.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;690&quot; data-start=&quot;687&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;707&quot; data-start=&quot;692&quot; data-ke-size=&quot;size26&quot;&gt;4. &lt;b&gt;해결 방법&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;836&quot; data-start=&quot;709&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;762&quot; data-start=&quot;709&quot;&gt;&lt;b&gt;Mock 객체의 리턴값을 명확히 지정&lt;/b&gt;&lt;br /&gt;(테스트용 데이터는 직접 만들어서 사용)&lt;/li&gt;
&lt;li data-end=&quot;798&quot; data-start=&quot;763&quot;&gt;&lt;b&gt;엔터티/DTO 클래스에 id까지 포함한 생성자를 추가&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;836&quot; data-start=&quot;799&quot;&gt;테스트 흐름/방식(단위테스트 vs 통합테스트) 구분 명확히 하기&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;841&quot; data-start=&quot;838&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;857&quot; data-start=&quot;843&quot; data-ke-size=&quot;size26&quot;&gt;5. &lt;b&gt;배운 점&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1017&quot; data-start=&quot;859&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;906&quot; data-start=&quot;859&quot;&gt;Mock 기반 단위 테스트에선 실제 DB와는 다르게 동작한다는 사실을 인지해야 함&lt;/li&gt;
&lt;li data-end=&quot;932&quot; data-start=&quot;907&quot;&gt;모든 테스트 데이터는 직접 세팅해줘야 한다&lt;/li&gt;
&lt;li data-end=&quot;977&quot; data-start=&quot;933&quot;&gt;에러 로그, println 등으로 중간값을 찍으며 원인 추적하는 과정이 중요&lt;/li&gt;
&lt;li data-end=&quot;1017&quot; data-start=&quot;978&quot;&gt;테스트 목적(단위/통합)에 따라 테스트 방식/코드 작성법이 달라진다&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Archive/예전 TIL</category>
      <author>khu2172</author>
      <guid isPermaLink="true">https://khu2172.tistory.com/83</guid>
      <comments>https://khu2172.tistory.com/83#entry83comment</comments>
      <pubDate>Thu, 10 Jul 2025 15:06:06 +0900</pubDate>
    </item>
    <item>
      <title>[트러블슈팅] 윈도우 한글 경로(ClassNotFoundException)로 인한 자바/테스트 에러</title>
      <link>https://khu2172.tistory.com/82</link>
      <description>&lt;h2 data-end=&quot;204&quot; data-start=&quot;189&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 현상&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;279&quot; data-start=&quot;206&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;225&quot; data-start=&quot;206&quot;&gt;&lt;b&gt;메인 메소드 실행은 정상&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;279&quot; data-start=&quot;226&quot;&gt;&lt;b&gt;JUnit 테스트, Gradle 빌드, 외부 명령 실행 등에서 아래와 같은 에러 발생&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;오류: 기본 클래스 worker.org.gradle.process.internal.worker&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;.GradleWorkerMain을(를) &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;찾거나 로드할 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;원인: java.lang.ClassNotFoundException: worker.org.gradle&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;.process.internal.worker.GradleWorkerMain &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;524&quot; data-start=&quot;476&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;524&quot; data-start=&quot;476&quot;&gt;추가로, JAVA_HOME/PATH 에러, 파이프 닫힘 등 부가적 메시지 반복 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;529&quot; data-start=&quot;526&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;554&quot; data-start=&quot;531&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;원인 파악을 위한 시도들&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;891&quot; data-start=&quot;556&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;660&quot; data-start=&quot;556&quot;&gt;&lt;b&gt;JDK/Gradle 재설치&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;660&quot; data-start=&quot;581&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;606&quot; data-start=&quot;581&quot;&gt;JDK, Gradle 최신 버전으로 재설치&lt;/li&gt;
&lt;li data-end=&quot;636&quot; data-start=&quot;610&quot;&gt;환경변수 JAVA_HOME, Path 재설정&lt;/li&gt;
&lt;li data-end=&quot;660&quot; data-start=&quot;640&quot;&gt;&amp;rarr; &lt;b&gt;여전히 동일 에러 발생&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;764&quot; data-start=&quot;662&quot;&gt;&lt;b&gt;인텔리제이 캐시/빌드 캐시 무효화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;764&quot; data-start=&quot;691&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;743&quot; data-start=&quot;691&quot;&gt;File &amp;gt; Invalidate Caches, .gradle/.idea 폴더 삭제 등 시도&lt;/li&gt;
&lt;li data-end=&quot;764&quot; data-start=&quot;747&quot;&gt;&amp;rarr; &lt;b&gt;에러 해결 안 됨&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;891&quot; data-start=&quot;766&quot;&gt;&lt;b&gt;프로젝트 경로/환경변수 점검&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;891&quot; data-start=&quot;792&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;816&quot; data-start=&quot;792&quot;&gt;JDK/Gradle 경로가 정상인지 확인&lt;/li&gt;
&lt;li data-end=&quot;857&quot; data-start=&quot;820&quot;&gt;CMD에서 java -version, gradle -v 등 실행&lt;/li&gt;
&lt;li data-end=&quot;891&quot; data-start=&quot;861&quot;&gt;&amp;rarr; &lt;b&gt;콘솔에서는 정상, 테스트에서는 에러 반복&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;896&quot; data-start=&quot;893&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;926&quot; data-start=&quot;898&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결국 원인은 &amp;lsquo;한글 계정(경로)&amp;rsquo;&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1106&quot; data-start=&quot;928&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1020&quot; data-start=&quot;928&quot;&gt;윈도우 사용자 폴더(C:\Users\한글계정명) 등&lt;br /&gt;&lt;b&gt;계정명에 한글이 포함된 상태에서 JDK/Gradle 등 개발 도구가 경로를 &lt;/b&gt;&lt;b&gt;제대로 인식하지 못함&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1106&quot; data-start=&quot;1021&quot;&gt;&lt;b&gt;IDE(인텔리제이)에서 메인 메소드는 잘 동작해도&lt;/b&gt;&lt;br /&gt;JUnit/Gradle 등은 OS의 환경변수 및 경로 인코딩에 더 민감해서 문제 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1111&quot; data-start=&quot;1108&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1145&quot; data-start=&quot;1113&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;최종 해결법: 영문 계정으로 마이그레이션&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1345&quot; data-start=&quot;1147&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1187&quot; data-start=&quot;1147&quot;&gt;&lt;b&gt;영문명 새 계정 생성, 관리자 권한 부여&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1217&quot; data-start=&quot;1188&quot;&gt;&lt;b&gt;필요한 프로젝트/자료만 새 계정으로 복사&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1256&quot; data-start=&quot;1218&quot;&gt;&lt;b&gt;인텔리제이, JDK, Gradle 등 개발 툴 새로 설치&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1301&quot; data-start=&quot;1257&quot;&gt;&lt;b&gt;JAVA_HOME, Path 등 환경변수 &amp;ldquo;영문 경로&amp;rdquo;로 다시 세팅&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1345&quot; data-start=&quot;1302&quot;&gt;&lt;b&gt;테스트/Gradle 빌드/외부 도구 등 모든 기능 정상 동작 확인&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;1350&quot; data-start=&quot;1347&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1364&quot; data-start=&quot;1352&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;교훈&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1516&quot; data-start=&quot;1366&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1417&quot; data-start=&quot;1366&quot;&gt;&lt;b&gt;윈도우 환경에서 개발하려면&lt;br /&gt;&amp;lsquo;영문 계정/영문 경로&amp;rsquo;는 선택이 아니라 필수!&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1464&quot; data-start=&quot;1418&quot;&gt;여러 환경설정/재설치만으로는&lt;br /&gt;&amp;lsquo;한글 경로&amp;rsquo; 문제를 완전히 해결할 수 없음&lt;/li&gt;
&lt;li data-end=&quot;1516&quot; data-start=&quot;1465&quot;&gt;트러블슈팅 과정 자체도 큰 경험!&lt;br /&gt;(이후 환경이 꼬였을 때 빠른 원인 파악 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1521&quot; data-start=&quot;1518&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1540&quot; data-start=&quot;1523&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;요약&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1767&quot; data-start=&quot;1546&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1651&quot; data-start=&quot;1546&quot;&gt;&lt;b&gt;에러 메시지&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1651&quot; data-start=&quot;1563&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1651&quot; data-start=&quot;1563&quot;&gt;ClassNotFoundException: worker.org.gradle.process.internal.worker.GradleWorkerMain&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1712&quot; data-start=&quot;1652&quot;&gt;&lt;b&gt;해결 위해 시도한 것들&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1712&quot; data-start=&quot;1675&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1712&quot; data-start=&quot;1675&quot;&gt;JDK/Gradle 재설치, 환경변수 재설정, 캐시 삭제 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1767&quot; data-start=&quot;1713&quot;&gt;&lt;b&gt;결국 한글 경로(계정) 때문이었음&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1767&quot; data-start=&quot;1742&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1767&quot; data-start=&quot;1742&quot;&gt;영문 계정으로 마이그레이션 후 완전 해결!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Archive/예전 TIL</category>
      <author>khu2172</author>
      <guid isPermaLink="true">https://khu2172.tistory.com/82</guid>
      <comments>https://khu2172.tistory.com/82#entry82comment</comments>
      <pubDate>Tue, 8 Jul 2025 23:29:47 +0900</pubDate>
    </item>
    <item>
      <title>JWT(Json Web Token)란?</title>
      <link>https://khu2172.tistory.com/81</link>
      <description>&lt;p data-end=&quot;260&quot; data-start=&quot;78&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;JWT&lt;/b&gt;는 &lt;b&gt;Json Web Token&lt;/b&gt;의 약자로, 웹 또는 모바일 환경에서 사용자 인증(Authentication)을 위해 사용되는 &lt;b&gt;토큰 기반 인증 방식&lt;/b&gt;이다.&lt;br /&gt;로그인 후 서버가 발급한 토큰을 클라이언트가 저장하고, 이후 요청마다 해당 토큰을 함께 전송함으로써 사용자를 식별하고 권한을 확인한다.&lt;/p&gt;
&lt;hr data-end=&quot;265&quot; data-start=&quot;262&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;280&quot; data-start=&quot;267&quot; data-ke-size=&quot;size26&quot;&gt;JWT의 구조&lt;/h2&gt;
&lt;p data-end=&quot;354&quot; data-start=&quot;282&quot; data-ke-size=&quot;size16&quot;&gt;JWT는 총 &lt;b&gt;3개의 구성 요소&lt;/b&gt;로 이루어져 있으며, 각각 &lt;b&gt;Base64Url 방식으로 인코딩&lt;/b&gt;되어&lt;/p&gt;
&lt;p data-end=&quot;354&quot; data-start=&quot;282&quot; data-ke-size=&quot;size16&quot;&gt;'&lt;b&gt;.&lt;/b&gt;(dot)'으로 연결된다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;628&quot; data-start=&quot;356&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;417&quot; data-start=&quot;356&quot;&gt;&lt;b&gt;Header&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;417&quot; data-start=&quot;375&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;417&quot; data-start=&quot;375&quot;&gt;토큰의 타입(JWT)과 해싱 알고리즘(예: HS256) 정보가 담긴다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;505&quot; data-start=&quot;419&quot;&gt;&lt;b&gt;Payload&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;505&quot; data-start=&quot;439&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;468&quot; data-start=&quot;439&quot;&gt;실제 토큰에 담고 싶은 사용자 정보가 포함된다.&lt;/li&gt;
&lt;li data-end=&quot;505&quot; data-start=&quot;472&quot;&gt;이 안의 정보를 Claim(클레임)이라 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;628&quot; data-start=&quot;507&quot;&gt;&lt;b&gt;Signature&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;628&quot; data-start=&quot;529&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;594&quot; data-start=&quot;529&quot;&gt;Header와 Payload를 조합한 후, 서버의 비밀 키(SECRET_KEY)를 사용해 서명한 값이다.&lt;/li&gt;
&lt;li data-end=&quot;628&quot; data-start=&quot;598&quot;&gt;토큰이 위변조되지 않았는지 검증하는 역할을 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;633&quot; data-start=&quot;630&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;654&quot; data-start=&quot;635&quot; data-ke-size=&quot;size26&quot;&gt;Claim(클레임)이란?&lt;/h2&gt;
&lt;p data-end=&quot;738&quot; data-start=&quot;656&quot; data-ke-size=&quot;size16&quot;&gt;Claim은 &lt;b&gt;Payload 안에 담기는 정보 조각&lt;/b&gt;이며, &lt;b&gt;key-value 쌍&lt;/b&gt;으로 구성된다.&lt;br /&gt;Claim의 종류는 다음과 같다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;970&quot; data-start=&quot;740&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;825&quot; data-start=&quot;740&quot;&gt;&lt;b&gt;등록된(Registered) Claim&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;825&quot; data-start=&quot;772&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;825&quot; data-start=&quot;772&quot;&gt;iss(발급자), exp(만료시간), sub(주제) 등 표준으로 정의된 클레임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;893&quot; data-start=&quot;826&quot;&gt;&lt;b&gt;공개(Public) Claim&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;893&quot; data-start=&quot;853&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;893&quot; data-start=&quot;853&quot;&gt;충돌을 방지하기 위해 공개적으로 정의되거나 URI로 명시된 클레임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;970&quot; data-start=&quot;894&quot;&gt;&lt;b&gt;비공개(Private) Claim&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;970&quot; data-start=&quot;923&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;970&quot; data-start=&quot;923&quot;&gt;발급자와 사용자 간 약속된 커스텀 정보 (예: userId, role 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;975&quot; data-start=&quot;972&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1001&quot; data-start=&quot;977&quot; data-ke-size=&quot;size26&quot;&gt;Signature(서명)의 역할&lt;/h2&gt;
&lt;p data-end=&quot;1111&quot; data-start=&quot;1003&quot; data-ke-size=&quot;size16&quot;&gt;Signature는 토큰의 위조를 방지하기 위한 &lt;b&gt;검증 수단&lt;/b&gt;이다.&lt;br /&gt;Header와 Payload가 조작되면 서명이 유효하지 않게 되며, 서버는 이를 통해 &lt;b&gt;신뢰 여부를 판별&lt;/b&gt;한다.&lt;/p&gt;
&lt;hr data-end=&quot;1116&quot; data-start=&quot;1113&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1130&quot; data-start=&quot;1118&quot; data-ke-size=&quot;size26&quot;&gt;JWT의 특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1374&quot; data-start=&quot;1132&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1180&quot; data-start=&quot;1132&quot;&gt;&lt;b&gt;Stateless&lt;/b&gt;&lt;br /&gt;서버가 사용자 정보를 별도로 저장하지 않아도 됨&lt;/li&gt;
&lt;li data-end=&quot;1235&quot; data-start=&quot;1181&quot;&gt;&lt;b&gt;Self-contained&lt;/b&gt;&lt;br /&gt;사용자 정보를 토큰 안에 자체적으로 포함하고 있음&lt;/li&gt;
&lt;li data-end=&quot;1304&quot; data-start=&quot;1236&quot;&gt;&lt;b&gt;URL-safe&lt;/b&gt;&lt;br /&gt;Base64Url 인코딩 덕분에 URL 파라미터나 HTTP 헤더에 안전하게 사용 가능&lt;/li&gt;
&lt;li data-end=&quot;1374&quot; data-start=&quot;1305&quot;&gt;&lt;b&gt;Authorization 헤더 사용&lt;/b&gt;&lt;br /&gt;보통 Authorization: Bearer &amp;lt;토큰&amp;gt; 형태로 전송됨&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1379&quot; data-start=&quot;1376&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1391&quot; data-start=&quot;1381&quot; data-ke-size=&quot;size26&quot;&gt;주의사항&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1565&quot; data-start=&quot;1393&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1462&quot; data-start=&quot;1393&quot;&gt;Payload는 &lt;b&gt;암호화되지 않으며&lt;/b&gt;, 누구나 열람할 수 있으므로 &lt;b&gt;민감한 정보는 절대 포함하지 말아야&lt;/b&gt; 한다.&lt;/li&gt;
&lt;li data-end=&quot;1514&quot; data-start=&quot;1463&quot;&gt;반드시 만료 시간(exp)을 설정해 &lt;b&gt;토큰 탈취와 재사용을 방지&lt;/b&gt;해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;1565&quot; data-start=&quot;1515&quot;&gt;서명(Signature)이 유효하더라도, 정보 자체가 노출된다는 점을 인지해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1570&quot; data-start=&quot;1567&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1693&quot; data-start=&quot;1572&quot; data-ke-size=&quot;size16&quot;&gt;JWT는 인증 시스템을 간결하고 확장성 있게 만들어주는 강력한 도구이지만, &lt;b&gt;보안 설계에 대한 충분한 이해와 주의가 필요하다&lt;/b&gt;.&lt;br /&gt;올바르게 사용한다면 세션 방식보다 더 효율적인 인증 체계를 구축할 수 있다.&lt;/p&gt;</description>
      <category>Backend/Java &amp;amp; Spring</category>
      <author>khu2172</author>
      <guid isPermaLink="true">https://khu2172.tistory.com/81</guid>
      <comments>https://khu2172.tistory.com/81#entry81comment</comments>
      <pubDate>Sat, 5 Jul 2025 23:59:11 +0900</pubDate>
    </item>
    <item>
      <title>[트러블슈팅] MyBatis 매퍼(static context 에러) &amp;mdash; 객체 주입과 메서드 호출 실수</title>
      <link>https://khu2172.tistory.com/80</link>
      <description>&lt;h1 data-end=&quot;141&quot; data-start=&quot;83&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-end=&quot;154&quot; data-start=&quot;143&quot; data-ke-size=&quot;size26&quot;&gt;문제 상황&lt;/h2&gt;
&lt;p data-end=&quot;295&quot; data-start=&quot;156&quot; data-ke-size=&quot;size16&quot;&gt;MyBatis/Spring 프로젝트에서&lt;br /&gt;&lt;b&gt;매퍼 메서드를 &amp;ldquo;클래스명.메서드()&amp;rdquo;로 호출해서&lt;/b&gt;&lt;br /&gt;Non-static method 'findXXX' cannot be referenced from a static context&lt;br /&gt;에러가 발생!&lt;/p&gt;
&lt;hr data-end=&quot;300&quot; data-start=&quot;297&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;313&quot; data-start=&quot;302&quot; data-ke-size=&quot;size26&quot;&gt;에러 예시&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;598&quot; data-start=&quot;390&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;487&quot; data-start=&quot;390&quot;&gt;&lt;b&gt;설명:&lt;/b&gt;&lt;br /&gt;InquiryMapper는 MyBatis 매퍼 인터페이스(빈)&lt;br /&gt;findInquiryById는 &amp;ldquo;static 메서드&amp;rdquo;가 아님(=인스턴스 메서드)&lt;/li&gt;
&lt;li data-end=&quot;598&quot; data-start=&quot;488&quot;&gt;&lt;b&gt;에러:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;598&quot; data-start=&quot;502&quot;&gt;Non-static method 'findInquiryById(java.lang.Long)' cannot be referenced from a static context&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;603&quot; data-start=&quot;600&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;616&quot; data-start=&quot;605&quot; data-ke-size=&quot;size26&quot;&gt;원인 분석&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;794&quot; data-start=&quot;618&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;673&quot; data-start=&quot;618&quot;&gt;MyBatis 매퍼는&lt;br /&gt;&lt;b&gt;Spring이 &amp;ldquo;객체(빈)&amp;rdquo;로 만들어서 DI(주입)&lt;/b&gt; 해줌&lt;/li&gt;
&lt;li data-end=&quot;794&quot; data-start=&quot;674&quot;&gt;InquiryMapper.findInquiryById(id)처럼&lt;br /&gt;&amp;ldquo;클래스명으로 직접&amp;rdquo; static 메서드 호출하듯이 쓰면&lt;br /&gt;자바가 &amp;ldquo;static 메서드가 아닌데 왜 클래스명으로 부르냐?&amp;rdquo;고 에러!&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;799&quot; data-start=&quot;796&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;816&quot; data-start=&quot;801&quot; data-ke-size=&quot;size26&quot;&gt;올바른 사용 방법&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;957&quot; data-start=&quot;818&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;928&quot; data-start=&quot;818&quot;&gt;&lt;b&gt;매퍼 객체(빈)를 DI(의존성 주입) 받는다&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;928&quot; data-start=&quot;855&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;900&quot; data-start=&quot;855&quot;&gt;보통 final InquiryMapper inquiryMapper;로 선언&lt;/li&gt;
&lt;li data-end=&quot;928&quot; data-start=&quot;904&quot;&gt;생성자, @Autowired 등으로 주입&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;957&quot; data-start=&quot;930&quot;&gt;&lt;b&gt;객체(변수)로 메서드를 호출해야 한다&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;1451&quot; data-start=&quot;1448&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1464&quot; data-start=&quot;1453&quot; data-ke-size=&quot;size26&quot;&gt;교훈/정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1661&quot; data-start=&quot;1466&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1509&quot; data-start=&quot;1466&quot;&gt;MyBatis 매퍼 메서드는 &lt;b&gt;static이 아니라 인스턴스 메서드&lt;/b&gt;!&lt;/li&gt;
&lt;li data-end=&quot;1546&quot; data-start=&quot;1510&quot;&gt;&lt;b&gt;항상 &amp;ldquo;객체(빈)로 주입받아서&amp;rdquo; 메서드를 호출해야 한다&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1661&quot; data-start=&quot;1547&quot;&gt;InquiryMapper.findXXX(id); X (클래스명 호출 = static만 가능)&lt;br /&gt;inquiryMapper.findXXX(id); O (객체로 호출 = 인스턴스 메서드)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1666&quot; data-start=&quot;1663&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1680&quot; data-start=&quot;1668&quot; data-ke-size=&quot;size26&quot;&gt;한 줄 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MyBatis 매퍼는 반드시 &amp;lsquo;주입받은 객체&amp;rsquo;로 메서드를 호출해야 하며,&lt;br /&gt;클래스명.메서드()는 static에서만 쓸 수 있다!&lt;/p&gt;</description>
      <author>khu2172</author>
      <guid isPermaLink="true">https://khu2172.tistory.com/80</guid>
      <comments>https://khu2172.tistory.com/80#entry80comment</comments>
      <pubDate>Fri, 4 Jul 2025 18:32:35 +0900</pubDate>
    </item>
    <item>
      <title>[트러블슈팅] FK 무결성 오류와 로그인 미구현 상태에서 user_id 입력 문제</title>
      <link>https://khu2172.tistory.com/79</link>
      <description>&lt;h2 data-end=&quot;158&quot; data-start=&quot;147&quot; data-ke-size=&quot;size26&quot;&gt;문제 상황&lt;/h2&gt;
&lt;p data-end=&quot;283&quot; data-start=&quot;160&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot + MyBatis + MySQL 환경에서&lt;br /&gt;&lt;b&gt;문의글(inquiry) 생성 시 FK 무결성 오류&lt;/b&gt;가 발생했다.&lt;br /&gt;또, &lt;b&gt;로그인/인증 기능 없이 user_id를 자동 세팅하려다 문제가 생김.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;288&quot; data-start=&quot;285&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;304&quot; data-start=&quot;290&quot; data-ke-size=&quot;size26&quot;&gt;주요 에러/현상&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;530&quot; data-start=&quot;306&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;447&quot; data-start=&quot;306&quot;&gt;&lt;b&gt;FK 무결성 오류&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;447&quot; data-start=&quot;326&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;398&quot; data-start=&quot;326&quot;&gt;Cannot add or update a child row: a foreign key constraint fails ...&lt;/li&gt;
&lt;li data-end=&quot;447&quot; data-start=&quot;402&quot;&gt;Column 'user_id' cannot be null&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;530&quot; data-start=&quot;448&quot;&gt;&lt;b&gt;로그인 기능 없이 user_id 자동 세팅 시도&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;530&quot; data-start=&quot;485&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;530&quot; data-start=&quot;485&quot;&gt;서버가 로그인된 유저 정보를 알지 못해 user_id 값을 자동으로 넣지 못함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;535&quot; data-start=&quot;532&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;548&quot; data-start=&quot;537&quot; data-ke-size=&quot;size26&quot;&gt;원인 분석&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;784&quot; data-start=&quot;550&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;659&quot; data-start=&quot;550&quot;&gt;&lt;b&gt;FK 무결성 오류:&lt;/b&gt;&lt;br /&gt;inquiry 테이블의 user_id 값과&lt;br /&gt;user 테이블의 id 값이 일치하지 않았음&lt;/li&gt;
&lt;li data-end=&quot;784&quot; data-start=&quot;661&quot;&gt;&lt;b&gt;로그인/인증 미구현:&lt;/b&gt;&lt;br /&gt;서버가 &quot;현재 로그인한 유저&quot; 정보를 모름&lt;br /&gt;&amp;rarr; user_id를 클라이언트가 직접 입력해야만 INSERT 가능&lt;br /&gt;&amp;rarr; 자동 세팅 시도 시 null 또는 잘못된 값으로 저장됨&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;789&quot; data-start=&quot;786&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;802&quot; data-start=&quot;791&quot; data-ke-size=&quot;size26&quot;&gt;해결 방법&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1338&quot; data-start=&quot;804&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1057&quot; data-start=&quot;804&quot;&gt;&lt;b&gt;FK 무결성 오류 해결&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;928&quot; data-start=&quot;827&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;870&quot; data-start=&quot;827&quot;&gt;inquiry.user_id의 값이 user.id에 실제로 존재하는지 확인
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;900&quot; data-start=&quot;874&quot;&gt;확인 결과, inquiry.user_id의 값과 user.id의 값이 불일치했음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;928&quot; data-start=&quot;904&quot;&gt;로그인 기능 미구현으로 인하여 user_id 값을 &lt;br /&gt;클라이언트가 직접 입력하여INSERT 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1338&quot; data-start=&quot;1059&quot;&gt;&lt;b&gt;로그인 기능 없이 user_id 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1338&quot; data-start=&quot;1090&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1162&quot; data-start=&quot;1090&quot;&gt;&lt;b&gt;클라이언트(포스트맨 등)에서 user_id를 직접 JSON 바디에 입력해서 요청&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1338&quot; data-start=&quot;1283&quot;&gt;이후 로그인/인증 기능을 개발하면&lt;br /&gt;user_id를 자동으로 세팅하는 구조로 리팩토링&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;1343&quot; data-start=&quot;1340&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1359&quot; data-start=&quot;1345&quot; data-ke-size=&quot;size26&quot;&gt;교훈/체크리스트&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1548&quot; data-start=&quot;1361&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1427&quot; data-start=&quot;1361&quot;&gt;&lt;b&gt;FK(외래키) 무결성:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1427&quot; data-start=&quot;1384&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1427&quot; data-start=&quot;1384&quot;&gt;참조하는 값(user_id)은 반드시 user 테이블에 실제로 존재해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1548&quot; data-start=&quot;1428&quot;&gt;&lt;b&gt;로그인/인증 없이 user_id 자동 세팅은 불가능:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1548&quot; data-start=&quot;1468&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1505&quot; data-start=&quot;1468&quot;&gt;인증 미구현 단계에서는 user_id를 반드시 직접 입력해야 함&lt;/li&gt;
&lt;li data-end=&quot;1548&quot; data-start=&quot;1508&quot;&gt;인증 도입 후에는 서버가 로그인 정보로 user_id를 추출해서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Archive/예전 TIL</category>
      <author>khu2172</author>
      <guid isPermaLink="true">https://khu2172.tistory.com/79</guid>
      <comments>https://khu2172.tistory.com/79#entry79comment</comments>
      <pubDate>Wed, 2 Jul 2025 19:47:16 +0900</pubDate>
    </item>
    <item>
      <title>[트러블슈팅] @Controller vs @RestController, 404 에러 &amp;amp; 정상 동작 차이</title>
      <link>https://khu2172.tistory.com/78</link>
      <description>&lt;h2 data-end=&quot;193&quot; data-start=&quot;182&quot; data-ke-size=&quot;size26&quot;&gt;문제 상황&lt;/h2&gt;
&lt;p data-end=&quot;279&quot; data-start=&quot;195&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot에서 API를 개발하다가,&lt;br /&gt;&lt;b&gt;DB에는 데이터가 잘 들어가는데, Postman에선 404 Not Found 에러&lt;/b&gt;가 발생했다.&lt;/p&gt;
&lt;hr data-end=&quot;284&quot; data-start=&quot;281&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;297&quot; data-start=&quot;286&quot; data-ke-size=&quot;size26&quot;&gt;원인 분석&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;667&quot; data-start=&quot;299&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;420&quot; data-start=&quot;299&quot;&gt;InquiryController에 &lt;b&gt;@Controller&lt;/b&gt; 애노테이션을 붙이고, &lt;br /&gt;@PostMapping으로 API를 작성했다.&lt;/li&gt;
&lt;li data-end=&quot;420&quot; data-start=&quot;299&quot;&gt;하지만 &lt;b&gt;@RestController가 아닌 @Controller만 쓰면, &lt;br /&gt;기본적으로 &amp;ldquo;뷰(HTML 화면)&amp;rdquo;를 반환하려고 동작&lt;/b&gt;한다.&lt;/li&gt;
&lt;li data-end=&quot;420&quot; data-start=&quot;299&quot;&gt;API에서 리턴 값이 없거나, JSON/객체/문자열 등 &lt;br /&gt;데이터만 내려줄 때는 &lt;b&gt;@RestController&lt;/b&gt;를 사용해야 한다!&lt;/li&gt;
&lt;li data-end=&quot;420&quot; data-start=&quot;299&quot;&gt;이걸 놓치면, 요청 자체가 매핑이 안 되거나(특히 void 리턴 시), &lt;br /&gt;예상과 다른 동작(404, 응답 없음 등)이 발생한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;162&quot; data-origin-height=&quot;37&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6AubD/btsOVuEI8D0/hP719L0lQHjQGxAgw4GBFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6AubD/btsOVuEI8D0/hP719L0lQHjQGxAgw4GBFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6AubD/btsOVuEI8D0/hP719L0lQHjQGxAgw4GBFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6AubD%2FbtsOVuEI8D0%2FhP719L0lQHjQGxAgw4GBFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;162&quot; height=&quot;37&quot; data-origin-width=&quot;162&quot; data-origin-height=&quot;37&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;119&quot; data-origin-height=&quot;22&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFPIHY/btsOUX8xEbk/gj6hO9zrZ3VLNvhEUqR491/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFPIHY/btsOUX8xEbk/gj6hO9zrZ3VLNvhEUqR491/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFPIHY/btsOUX8xEbk/gj6hO9zrZ3VLNvhEUqR491/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFPIHY%2FbtsOUX8xEbk%2Fgj6hO9zrZ3VLNvhEUqR491%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;119&quot; height=&quot;22&quot; data-origin-width=&quot;119&quot; data-origin-height=&quot;22&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-end=&quot;672&quot; data-start=&quot;669&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;685&quot; data-start=&quot;674&quot; data-ke-size=&quot;size26&quot;&gt;해결 과정&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;881&quot; data-start=&quot;687&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;803&quot; data-start=&quot;687&quot;&gt;@Controller 애노테이션을 &lt;br /&gt;@RestController 애노테이션으로 &lt;b&gt;변경&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;789&quot; data-start=&quot;719&quot;&gt;서버 재시작&lt;/li&gt;
&lt;li data-end=&quot;789&quot; data-start=&quot;719&quot;&gt;다시 Postman에서 요청 &lt;br /&gt;&amp;rarr; &lt;b&gt;정상 200 OK 응답 &amp;amp; DB에도 데이터 정상 입력!&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;125&quot; data-origin-height=&quot;16&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cc8bkR/btsOV1JiPCp/TMl3RUQxbWVVukKkiUoZxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cc8bkR/btsOV1JiPCp/TMl3RUQxbWVVukKkiUoZxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cc8bkR/btsOV1JiPCp/TMl3RUQxbWVVukKkiUoZxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcc8bkR%2FbtsOV1JiPCp%2FTMl3RUQxbWVVukKkiUoZxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;125&quot; height=&quot;16&quot; data-origin-width=&quot;125&quot; data-origin-height=&quot;16&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;91&quot; data-origin-height=&quot;33&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AdgcK/btsOVbSZDCS/ZmcujkBKD1lkz1wTKGj3UK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AdgcK/btsOVbSZDCS/ZmcujkBKD1lkz1wTKGj3UK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AdgcK/btsOVbSZDCS/ZmcujkBKD1lkz1wTKGj3UK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAdgcK%2FbtsOVbSZDCS%2FZmcujkBKD1lkz1wTKGj3UK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;91&quot; height=&quot;33&quot; data-origin-width=&quot;91&quot; data-origin-height=&quot;33&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-end=&quot;886&quot; data-start=&quot;883&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;901&quot; data-start=&quot;888&quot; data-ke-size=&quot;size26&quot;&gt;느낀 점/정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1170&quot; data-start=&quot;903&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;968&quot; data-start=&quot;903&quot;&gt;&lt;b&gt;@RestController는 &amp;ldquo;데이터(API)&amp;rdquo; 반환, &lt;br /&gt;@Controller는 &amp;ldquo;뷰(화면)&amp;rdquo; 반환용&lt;/b&gt;이다!&lt;/li&gt;
&lt;li data-end=&quot;1031&quot; data-start=&quot;969&quot;&gt;데이터만 반환하는 API는 @RestController로 만드는 게 정답&lt;/li&gt;
&lt;li data-end=&quot;1088&quot; data-start=&quot;1032&quot;&gt;리턴 값이 없어도, JSON이 아니어도, &lt;br /&gt;&amp;ldquo;API라면 무조건 @RestController&amp;rdquo;&lt;/li&gt;
&lt;li data-end=&quot;1170&quot; data-start=&quot;1089&quot;&gt;&lt;b&gt;404 에러가 났는데 DB에는 값이 들어간다면,&lt;br /&gt;엔드포인트 매핑이나 애노테이션(@RestController)부터 꼭 점검할 것!&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1175&quot; data-start=&quot;1172&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1185&quot; data-start=&quot;1177&quot; data-ke-size=&quot;size26&quot;&gt;  참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1402&quot; data-start=&quot;1186&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1328&quot; data-start=&quot;1186&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-rest-controller.html&quot; data-end=&quot;1328&quot; data-start=&quot;1188&quot;&gt;공식문서: @RestController vs @Controller&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;1402&quot; data-start=&quot;1329&quot;&gt;&lt;a href=&quot;https://spring.io/guides/gs/rest-service/&quot; data-end=&quot;1402&quot; data-start=&quot;1331&quot;&gt;Spring 공식 블로그 REST API 만들기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Archive/예전 TIL</category>
      <author>khu2172</author>
      <guid isPermaLink="true">https://khu2172.tistory.com/78</guid>
      <comments>https://khu2172.tistory.com/78#entry78comment</comments>
      <pubDate>Sat, 28 Jun 2025 05:56:10 +0900</pubDate>
    </item>
  </channel>
</rss>