<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Neo RC</title>
    <link>https://neorc.tistory.com/</link>
    <description>안녕하세요. 저는 IT 프로그램 개발 및 컨설팅 분야에서 20년 이상의 경력을 쌓아온 네오입니다.
대형 IT 기업에서 개발자로 시작해 프로젝트 매니저, 솔루션 아키텍트를 거쳐 현재는 IT 컨설턴트로 일하고 있습니다.
주요 경력으로는 경영지원, 제조, 유통 등 다양한 산업 분야의 시스템 구축 프로젝트를 수행한 바 있습니다. 
앞으로도 끊임없는 학습과 도전을 통해 IT 분야의 전문성을 더욱 높이고, 실질적인 가치를 제공하는 IT 전문가로 성장해 나가겠습니다</description>
    <language>ko</language>
    <pubDate>Mon, 6 Apr 2026 07:06:58 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>neorc</managingEditor>
    <image>
      <title>Neo RC</title>
      <url>https://tistory1.daumcdn.net/tistory/7687237/attach/be336c1503bd4cec965bfd4d15a53321</url>
      <link>https://neorc.tistory.com</link>
    </image>
    <item>
      <title>JQuery 윈도우 이벤트 정리</title>
      <link>https://neorc.tistory.com/42</link>
      <description>&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jQuery에서 window 객체와 관련된 이벤트는 주로 브라우저 창의 상태 변화나 사용자 상호작용을 감지하는 데 사용됩니다. 이러한 이벤트들은 $(window)를 대상으로 바인딩하며, 페이지 로드, 크기 변경, 스크롤 등을 효율적으로 처리할 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;주요 이벤트 목록&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jQuery window 이벤트는 다음과 같습니다. 각 이벤트는 $(window).on('eventName', function(){}) 형태로 사용하거나 단축 메서드(예: .load())로 호출할 수 있습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;
&lt;div&gt;이벤트 이름설명예시 사용법&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;이벤트 이름설명예시 사용법
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;load&lt;/td&gt;
&lt;td&gt;모든 리소스(이미지, CSS 등)가 로드 완료 시 발생. 페이지 전체 로딩 후 실행.&lt;/td&gt;
&lt;td&gt;$(window).on('load', function(){ console.log('로드 완료'); }); &lt;span&gt;&lt;/span&gt;&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;resize&lt;/td&gt;
&lt;td&gt;창 크기가 변경될 때 발생. 반응형 디자인에 유용.&lt;/td&gt;
&lt;td&gt;$(window).on('resize', function(){ console.log('크기 변경'); });&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;scroll&lt;/td&gt;
&lt;td&gt;스크롤바 이동 시 발생. 무한 스크롤 등에 활용.&lt;/td&gt;
&lt;td&gt;$(window).on('scroll', function(){ console.log('스크롤 중'); });&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;unload&lt;/td&gt;
&lt;td&gt;페이지가 언로드(닫힘)될 때 발생. 정리 작업에 사용.&lt;/td&gt;
&lt;td&gt;$(window).on('unload', function(){ /* 저장 */ }); &lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;error&lt;/td&gt;
&lt;td&gt;로딩 중 에러 발생 시. 이미지 등 실패 처리.&lt;/td&gt;
&lt;td&gt;$(window).on('error', function(){ console.log('에러'); }); &lt;span&gt;&lt;/span&gt;&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ready&lt;/td&gt;
&lt;td&gt;document 준비 완료(DOM 로드). window가 아닌 document에서 주로 사용되지만 window와 연계.&lt;/td&gt;
&lt;td&gt;$(document).ready(function(){});&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;바인딩 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트는 .on() 메서드로 여러 개를 한 번에 연결할 수 있습니다. 예: $(window).on('resize scroll', function(){}); 이는 성능 최적화에 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 단축 메서드도 지원: .resize(), .scroll() 등으로 간단히 사용하세요. 이벤트 핸들러 내에서 $(this)를 사용해 window 객체에 접근할 수 있습니다.&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;실전 예제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크롤 이벤트로 헤더를 숨기는 코드:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-testid=&quot;code-language-indicator&quot;&gt;text&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt;$(window).scroll(function(){ &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt; if ($(this).scrollTop() &amp;gt; 100) { &lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt; $('header').fadeOut(); &lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;}); &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 window 이벤트는 모바일/데스크톱 반응형 UI에 필수적입니다.&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그램/Javascript</category>
      <category>Event</category>
      <category>Focus</category>
      <category>JQuery</category>
      <category>onload</category>
      <category>resize</category>
      <category>scroll</category>
      <category>window</category>
      <category>윈도우</category>
      <category>이벤트</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/42</guid>
      <comments>https://neorc.tistory.com/42#entry42comment</comments>
      <pubDate>Tue, 17 Mar 2026 14:04:41 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 윈도우 이벤트 정리</title>
      <link>https://neorc.tistory.com/41</link>
      <description>&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트의 window 객체는 브라우저 창과 관련된 다양한 이벤트를 제공합니다. 이 이벤트들은 페이지 로드, 크기 변경, 스크롤 등 창 상태 변화를 감지할 때 사용되며, 주로 addEventListener()로 등록합니다.&lt;/p&gt;
&lt;h2 id=&quot;window&quot; data-ke-size=&quot;size26&quot;&gt;주요 Window 이벤트 목록&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Window 객체에서 청취할 수 있는 핵심 이벤트는 다음과 같습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;이벤트 이름설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;load&lt;/td&gt;
&lt;td&gt;페이지와 모든 리소스(이미지, 스타일시트 등)가 완전히 로드될 때 발생 &lt;span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;resize&lt;/td&gt;
&lt;td&gt;창 크기가 변경될 때 발생&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;scroll&lt;/td&gt;
&lt;td&gt;창이나 문서가 스크롤될 때 발생&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;unload&lt;/td&gt;
&lt;td&gt;페이지가 언로드될 때 발생&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;beforeunload&lt;/td&gt;
&lt;td&gt;페이지가 언로드되기 직전 발생&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;blur&lt;/td&gt;
&lt;td&gt;창이 포커스를 잃을 때 &lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;focus&lt;/td&gt;
&lt;td&gt;창이 포커스를 얻을 때 &lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;online&lt;/td&gt;
&lt;td&gt;네트워크 연결이 복구될 때 &lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;offline&lt;/td&gt;
&lt;td&gt;네트워크 연결이 끊길 때&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;storage&lt;/td&gt;
&lt;td&gt;localStorage나 sessionStorage가 변경될 때 &lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 orientationchange(기기 회전), hashchange(URL 해시 변경), pagehide(페이지 숨김) 등이 있습니다.&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;이벤트 등록 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;window 이벤트는 addEventListener()나 속성(onload 등)으로 등록합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;addEventListener(): 여러 핸들러 등록 가능, 권장 방식.&lt;/li&gt;
&lt;li&gt;속성 방식: window.onresize = function() { ... }.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;샘플 코드 예제&lt;/h2&gt;
&lt;h2 id=&quot;1----load&quot; data-ke-size=&quot;size26&quot;&gt;1. 페이지 로드 이벤트 (load)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-testid=&quot;code-language-indicator&quot;&gt;javascript&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;'load'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #b294bb;&quot;&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt; console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;'페이지가 완전히 로드되었습니다.'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #969896;&quot;&gt;// 초기화 작업 수행&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이벤트는 DOMContentLoaded보다 늦게 발생하며 모든 리소스 로드를 기다립니다.&lt;/p&gt;
&lt;h2 id=&quot;2----resize&quot; data-ke-size=&quot;size26&quot;&gt;2. 창 크기 변경 (resize)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-testid=&quot;code-language-indicator&quot;&gt;javascript&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span style=&quot;color: #b294bb;&quot;&gt;function&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;updateSize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt; console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;창 크기: &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;innerWidth&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt; x &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;innerHeight&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;'resize'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; updateSize&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈번한 호출을 피하려면 throttle 적용을 고려하세요.&lt;/p&gt;
&lt;h2 id=&quot;3---scroll&quot; data-ke-size=&quot;size26&quot;&gt;3. 스크롤 이벤트 (scroll)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-testid=&quot;code-language-indicator&quot;&gt;javascript&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;'scroll'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #b294bb;&quot;&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #b294bb;&quot;&gt;const&lt;/span&gt;&lt;span&gt; scrollY &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;scrollY&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt; console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;스크롤 위치: &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;scrollY&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #b294bb;&quot;&gt;if&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;scrollY &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #de935f;&quot;&gt;100&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt; document&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;background &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;'lightgray'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #969896;&quot;&gt;// 예시 효과&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능을 위해 debounce/throttle 사용 권장.&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;4--focusblur&quot; data-ke-size=&quot;size26&quot;&gt;4. 포커스/블러 (focus/blur)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-testid=&quot;code-language-indicator&quot;&gt;javascript&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;'focus'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;'창 포커스'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6; text-align: right;&quot;&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;'blur'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #c5c8c6;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b5bd68;&quot;&gt;'창 블러'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탭 전환 시 유용합니다.&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이벤트들은 브라우저 호환성이 높아 대부분 지원되며, 모바일에서도 잘 작동합니다.&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>프로그램/Javascript</category>
      <category>addevent</category>
      <category>Focus</category>
      <category>javascript</category>
      <category>onload</category>
      <category>resize</category>
      <category>scroll</category>
      <category>window</category>
      <category>윈도우이벤트</category>
      <category>자바스크립트</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/41</guid>
      <comments>https://neorc.tistory.com/41#entry41comment</comments>
      <pubDate>Tue, 17 Mar 2026 14:01:53 +0900</pubDate>
    </item>
    <item>
      <title>Docker 기본 개념 및 사용법-02</title>
      <link>https://neorc.tistory.com/40</link>
      <description>&lt;h2 id=&quot;1-docker&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;1. Docker 핵심 개념 요약&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Build &amp;rarr; Ship &amp;rarr; Run&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;세 단계로 동작합니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://shifttotech.co.in/blog/complete-docker-tutorial-2025&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Image:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;실행 환경의 스냅샷(읽기 전용 템플릿)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Container:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이미지를 기반으로 실행된 격리된 프로세스&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Volume:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;컨테이너 삭제 후에도 데이터를 보존하는 스토리지&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://docs.docker.com/engine/storage/volumes/&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;​&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Network:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;컨테이너 간 통신을 제어하는 가상 네트워크&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://noobtomaster.com/docker/configuring-services-networks-volumes-and-environment-variables/&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;​&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;2&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2. 컨테이너 라이프사이클&lt;/h2&gt;
&lt;h2 id=&quot;&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;기본 실행 명령어&lt;/h2&gt;
&lt;pre id=&quot;code_1772083586664&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d -p 8080:80 --name my-nginx nginx   # 백그라운드 실행
docker ps                                          # 실행 중인 컨테이너 목록
docker ps -a                                       # 중단된 컨테이너 포함 전체 목록
docker stop my-nginx                               # 우아한 종료 (SIGTERM)
docker kill my-nginx                               # 강제 종료 (SIGKILL)
docker start my-nginx                              # 중단된 컨테이너 재시작
docker rm my-nginx                                 # 컨테이너 삭제
docker rm -f my-nginx                              # 실행 중인 컨테이너 강제 삭제&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;docker run&lt;span&gt;&amp;nbsp;&lt;/span&gt;주요 옵션&lt;/h2&gt;
&lt;div style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot;&gt;
&lt;div style=&quot;background-color: oklch(0.9893 0.003 48.72);&quot;&gt;옵션설명예시
&lt;table style=&quot;text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;-d&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;백그라운드 실행&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;-d&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;-p&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;포트 매핑 (호스트:컨테이너)&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;-p 3306:3306&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;--name&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;컨테이너 이름 지정&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;--name my-app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;-e&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;환경 변수 설정&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;-e DB_HOST=localhost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;-v&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;볼륨 마운트&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;-v /host/path:/container/path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;--network&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;네트워크 연결&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;--network my-net&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;--rm&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;종료 시 자동 삭제&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;--rm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;-it&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;인터랙티브 터미널&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;-it ubuntu bash&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: oklch(0.9798 0.005 78.3);&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;3&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;3. 디버깅 명령어 (엔지니어 필수)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실무에서 가장 자주 쓰는 명령어들입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1772083605868&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker logs -f my-nginx              # 실시간 로그 스트리밍
docker exec -it my-nginx /bin/bash   # 실행 중인 컨테이너 내부 쉘 접속
docker inspect my-nginx              # JSON 형식으로 상세 정보 출력 (IP, 마운트 등)
docker stats                         # CPU, 메모리 실시간 모니터링
docker cp my-nginx:/etc/nginx.conf . # 컨테이너에서 파일 복사&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;4-dockerfile&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;4. Dockerfile 작성 (이미지 빌드)&lt;/h2&gt;
&lt;h2 style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;기본 구조&lt;/h2&gt;
&lt;pre id=&quot;code_1772083617677&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1. 베이스 이미지 (가벼운 alpine 권장)
FROM node:18-alpine

# 2. 작업 디렉토리 설정
WORKDIR /app

# 3. 의존성 먼저 복사 (캐시 레이어 활용)
COPY package*.json ./
RUN npm ci --only=production

# 4. 소스 코드 복사
COPY . .

# 5. 포트 선언
EXPOSE 3000

# 6. 실행 명령어
CMD [&quot;node&quot;, &quot;server.js&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;multi-stage-build&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;고급: 멀티 스테이지 빌드 (Multi-Stage Build)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;빌드 도구를 최종 이미지에서 제거하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이미지 크기를 극적으로 줄이는&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;핵심 기법입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1772083631725&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Stage 1: 빌드 환경 (무거운 빌드 도구 포함)
FROM node:18 AS builder
WORKDIR /app
COPY . .
RUN npm install &amp;amp;&amp;amp; npm run build  # 빌드 아티팩트 생성

# Stage 2: 실행 환경 (빌드 도구 없이 결과물만 복사)
FROM node:18-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist  # builder 스테이지에서 결과물만 복사
COPY --from=builder /app/node_modules ./node_modules
CMD [&quot;node&quot;, &quot;dist/server.js&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식으로 이미지 크기를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;수백 MB &amp;rarr; 수십 MB&lt;/b&gt;로 줄일 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빌드 명령어:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1772083646361&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker build -t my-app:v1 .           # 기본 빌드
docker build --target production .    # 특정 스테이지만 빌드 (BuildKit 필요)
docker tag my-app:v1 username/my-app  # Docker Hub 배포용 태그
docker push username/my-app           # Docker Hub 업로드&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;5-volume&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;5. Volume (데이터 영속성)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너를 삭제하면 내부 데이터도 사라집니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Volume&lt;/b&gt;으로 데이터를 보존하세요.&lt;/p&gt;
&lt;pre id=&quot;code_1772083662397&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Named Volume (Docker가 관리, 운영 환경 권장)
docker run -v mysql_data:/var/lib/mysql mysql:8.4

# Bind Mount (로컬 디렉토리와 직접 연결, 개발 환경 권장)
docker run -v $(pwd)/src:/app/src my-app  # 코드 변경 즉시 반영

# 볼륨 관리
docker volume ls                      # 볼륨 목록
docker volume inspect mysql_data      # 볼륨 상세 정보
docker volume rm mysql_data           # 볼륨 삭제&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;6-network&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;6. Network (컨테이너 간 통신)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;같은 네트워크에 속한 컨테이너는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컨테이너 이름&lt;/b&gt;으로 서로 통신할 수 있습니다.&lt;span data-state=&quot;open&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://noobtomaster.com/docker/configuring-services-networks-volumes-and-environment-variables/&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1772083678691&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 사용자 정의 네트워크 생성
docker network create my-network

# 컨테이너를 동일 네트워크에 연결
docker run --network my-network --name db mysql:8.4
docker run --network my-network --name app my-app  # app에서 &quot;db&quot;라는 호스트명으로 DB 접근 가능&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;7-docker-compose&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;7. Docker Compose (멀티 컨테이너 관리)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여러 컨테이너 설정을 코드로 관리하는 실무 표준입니다.&lt;span data-state=&quot;open&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://stackoverflow.com/questions/29377853/how-can-i-use-environment-variables-in-docker-compose&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1772083693401&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - &quot;3000:3000&quot;
    environment:
      - DB_HOST=db          # 서비스 이름(db)이 곧 호스트명
      - DB_PASSWORD=${DB_PASSWORD}  # .env 파일에서 불러오기
    depends_on:
      - db
    volumes:
      - ./src:/app/src      # 개발 시 코드 실시간 반영

  db:
    image: mysql:8.4
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:  # Named volume 선언&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1772083704245&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose up -d          # 전체 서비스 백그라운드 실행
docker-compose up --build     # 이미지 재빌드 후 실행
docker-compose down           # 서비스 중단 + 컨테이너 삭제
docker-compose down -v        # 볼륨까지 삭제
docker-compose logs -f app    # 특정 서비스 로그 확인&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;8---cleanup&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;8. 리소스 정리 (Cleanup)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;도커를 쓰다 보면 미사용 이미지/컨테이너가 디스크를 잠식합니다.&lt;span data-state=&quot;open&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://shifttotech.co.in/blog/complete-docker-tutorial-2025&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1772083717569&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker system prune           # 미사용 컨테이너, 네트워크, 이미지 일괄 삭제
docker system prune -a        # 사용 중이 아닌 모든 이미지 포함 삭제
docker volume prune           # 미사용 볼륨 삭제
docker system df              # 도커가 사용 중인 디스크 용량 확인&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;best-practices&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;엔지니어 Best Practices 요약&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;.dockerignore&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일 필수 작성&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;node_modules,&lt;span&gt;&amp;nbsp;&lt;/span&gt;.git,&lt;span&gt;&amp;nbsp;&lt;/span&gt;.env&lt;span&gt;&amp;nbsp;&lt;/span&gt;등 제외&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://docs.docker.com/build/building/best-practices/&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;​&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;루트 사용자 금지&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;Dockerfile에&lt;span&gt;&amp;nbsp;&lt;/span&gt;USER node&lt;span&gt;&amp;nbsp;&lt;/span&gt;등 비루트 사용자 설정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;환경 변수 분리&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 비밀번호&amp;middot;API 키는&lt;span&gt;&amp;nbsp;&lt;/span&gt;.env&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일로 관리하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;.gitignore에 추가&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://stackoverflow.com/questions/29377853/how-can-i-use-environment-variables-in-docker-compose&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;​&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;레이어 캐싱 활용&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 변경 빈도가 낮은 명령어(의존성 설치)를 소스 복사보다 앞에 배치&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://docs.docker.com/build/building/best-practices/&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;​&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;태그 관리&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;latest&lt;span&gt;&amp;nbsp;&lt;/span&gt;대신&lt;span&gt;&amp;nbsp;&lt;/span&gt;my-app:v1.2.3&lt;span&gt;&amp;nbsp;&lt;/span&gt;처럼 명시적 버전 태그 사용&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Tool/Docker</category>
      <category>Docker</category>
      <category>개념</category>
      <category>명령어</category>
      <category>사용법</category>
      <category>이미지</category>
      <category>컨테이너</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/40</guid>
      <comments>https://neorc.tistory.com/40#entry40comment</comments>
      <pubDate>Thu, 26 Feb 2026 14:29:39 +0900</pubDate>
    </item>
    <item>
      <title>Docker 기본 개념 및 사용법-01</title>
      <link>https://neorc.tistory.com/39</link>
      <description>&lt;h2 id=&quot;1-docker&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;1. Docker 핵심 아키텍처&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker는 애플리케이션 실행에 필요한 환경을 **이미지(Image)**라는 단위로 패키징하고, 이를 **컨테이너(Container)**라는 격리된 프로세스로 실행합니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Image (이미지):&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;애플리케이션 실행을 위한 읽기 전용 템플릿입니다. 소스 코드, 라이브러리, 종속성, 도구 등이 포함된 '클래스(Class)'와 같습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Container (컨테이너):&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이미지를 실행한 상태입니다. 이미지의 '인스턴스(Instance)'이며, 격리된 파일 시스템과 네트워크를 가집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Dockerfile:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이미지를 생성하는 명세서입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;FROM,&lt;span&gt;&amp;nbsp;&lt;/span&gt;RUN,&lt;span&gt;&amp;nbsp;&lt;/span&gt;COPY&lt;span&gt;&amp;nbsp;&lt;/span&gt;등의 명령어로 빌드 과정을 코드로 정의합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Docker Compose:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;여러 컨테이너(예: Web + DB)를 정의하고 실행하는 오케스트레이션 도구입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2--docker--build---ship---run&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2. 엔지니어의 Docker 워크플로우 (Build - Ship - Run)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가장 많이 사용하게 될 흐름은 다음과 같습니다.&lt;/p&gt;
&lt;h2 id=&quot;a-----run&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;A. 이미지 가져오기 및 실행 (Run)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가장 기본적인 사용법입니다. Docker Hub 등 레지스트리에서 이미지를 받아 실행합니다.&lt;/p&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1772083399390&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Nginx 웹 서버 실행 예시
docker run -d -p 8080:80 --name my-webserver nginx:latest&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;-d: 백그라운드 실행&lt;/li&gt;
&lt;li&gt;-p 8080:80: 호스트의 8080 포트를 컨테이너의 80 포트와 연결&lt;/li&gt;
&lt;li&gt;--name: 컨테이너 이름 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;b----build&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;B. 나만의 이미지 만들기 (Build)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트 루트에&lt;span&gt;&amp;nbsp;&lt;/span&gt;Dockerfile을 작성하여 커스텀 이미지를 빌드합니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://docs.docker.com/get-started/docker-overview/&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Dockerfile 예시 (Node.js):&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1772083422490&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1. 베이스 이미지 선택
FROM node:18-alpine

# 2. 작업 디렉토리 설정
WORKDIR /app

# 3. 의존성 파일 복사 및 설치 (캐싱 활용을 위해 소스보다 먼저)
COPY package*.json ./
RUN npm install

# 4. 소스 코드 복사
COPY . .

# 5. 실행 명령어 정의
CMD [&quot;npm&quot;, &quot;start&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빌드 및 실행:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1772083440120&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker build -t my-app:v1 .  # 현재 디렉토리(.)의 Dockerfile로 빌드
docker run my-app:v1&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;c----compose&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;C. 멀티 컨테이너 관리 (Compose)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실무에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;docker run&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령어를 일일이 치기보다&lt;span&gt;&amp;nbsp;&lt;/span&gt;docker-compose.yml&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일로 인프라를 코드화(IaC)하여 관리합니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://www.theserverside.com/blog/Coffee-Talk-Java-News-Stories-and-Opinions/Docker-run-vs-docker-compose-Whats-the-difference&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;​&lt;/span&gt;&lt;span data-state=&quot;closed&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;docker-compose.yml 예시:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1772083461276&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: '3.8'
services:
  web:
    build: .
    ports:
      - &quot;3000:3000&quot;
    depends_on:
      - db
  db:
    image: postgres:14
    volumes:
      - db_data:/var/lib/postgresql/data # 데이터 영속성 보장

volumes:
  db_data:&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실행:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1772083475234&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose up -d  # 서비스 전체 실행
docker-compose down   # 서비스 전체 중단 및 삭제&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;3&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;3. 필수 명령어 치트시트&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&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; background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;docker images: 다운로드된 이미지 목록 확인&lt;/li&gt;
&lt;li&gt;docker rmi [이미지ID]: 이미지 삭제&lt;/li&gt;
&lt;li&gt;docker build -t [이름] .: 이미지 빌드&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&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; background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;docker ps: 실행 중인 컨테이너 목록&lt;/li&gt;
&lt;li&gt;docker ps -a: 중지된 컨테이너 포함 전체 목록&lt;/li&gt;
&lt;li&gt;docker stop [ID]: 컨테이너 우아한 종료 (SIGTERM)&lt;/li&gt;
&lt;li&gt;docker kill [ID]: 컨테이너 강제 종료 (SIGKILL)&lt;/li&gt;
&lt;li&gt;docker rm [ID]: 컨테이너 삭제 (실행 중이면&lt;span&gt;&amp;nbsp;&lt;/span&gt;-f&lt;span&gt;&amp;nbsp;&lt;/span&gt;필요)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&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; background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;docker logs -f [ID]: 로그 실시간 확인 (엔지니어 필수 명령어)&lt;/li&gt;
&lt;li&gt;docker exec -it [ID] /bin/bash: 실행 중인 컨테이너 내부로 쉘 접속&lt;/li&gt;
&lt;li&gt;docker inspect [ID]: 컨테이너 상세 정보(IP, 볼륨 마운트 등) 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;4---best-practices&quot; style=&quot;background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;4. 엔지니어를 위한 Best Practices&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: oklch(0.9798 0.005 78.3); color: oklch(0.2642 0.013 93.9); text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;가벼운 베이스 이미지 사용:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;ubuntu&lt;span&gt;&amp;nbsp;&lt;/span&gt;대신&lt;span&gt;&amp;nbsp;&lt;/span&gt;alpine과 같은 최소 이미지를 사용하여 빌드 속도와 보안성을 높이세요.&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://testdriven.io/blog/docker-best-practices/&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;​&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;멀티 스테이지 빌드 (Multi-stage Build):&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;빌드 도구(예: JDK, Node 등)는 최종 이미지에서 제거하여 용량을 줄이세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;레이어 캐싱 활용:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;변경이 잦은 소스 코드(COPY . .)는&lt;span&gt;&amp;nbsp;&lt;/span&gt;package.json&lt;span&gt;&amp;nbsp;&lt;/span&gt;설치(RUN npm install)보다 나중에 배치해야 빌드 속도가 빨라집니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;.dockerignore 사용:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;.git,&lt;span&gt;&amp;nbsp;&lt;/span&gt;node_modules&lt;span&gt;&amp;nbsp;&lt;/span&gt;등 불필요한 파일이 빌드 컨텍스트에 포함되지 않도록 설정하세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;볼륨 사용:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터베이스 데이터나 로그 파일은 반드시&lt;span&gt;&amp;nbsp;&lt;/span&gt;Volume을 사용하여 컨테이너가 삭제되어도 데이터가 유실되지 않도록 하세요.&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-pplx-citation-url=&quot;https://docs.docker.com/engine/storage/&quot; data-pplx-citation=&quot;&quot;&gt;&lt;/span&gt;​&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Tool/Docker</category>
      <category>Docker</category>
      <category>개념</category>
      <category>사용법</category>
      <category>이미지</category>
      <category>컨테이너</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/39</guid>
      <comments>https://neorc.tistory.com/39#entry39comment</comments>
      <pubDate>Thu, 26 Feb 2026 14:25:35 +0900</pubDate>
    </item>
    <item>
      <title>명령어Tail 단순한 파일 읽기 도구가 아니다</title>
      <link>https://neorc.tistory.com/38</link>
      <description>&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리눅스 시스템 관리자(Administrator)나 백엔드 엔지니어에게&lt;span&gt;&amp;nbsp;&lt;/span&gt;tail은 단순한 파일 읽기 도구가 아니라,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서버의 맥박을 실시간으로 확인하는 청진기&lt;/b&gt;와 같습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실무에서 자주 쓰이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;필수 패턴&lt;/b&gt;과 고수들이 사용하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;고급 스킬&lt;/b&gt;을 나누어 정리해 드립니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;1. 관리자가 숨 쉬듯이 쓰는 필수 패턴 (Basic &amp;amp; Frequent)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가장 기본적이지만, 옵션 하나 차이로 업무 효율이 달라집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;패턴명령어 예시설명 및 사용 상황&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;실시간 모니터링&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;tail -f server.log&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;가장 기본.&lt;/b&gt; 로그가 쌓이는 즉시 화면에 뿌려줍니다. (Ctrl+C로 종료)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;마지막 N줄만 보기&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;tail -n 100 server.log&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;파일 전체를 열지 않고 &lt;b&gt;최근 100줄&lt;/b&gt;만 빠르게 확인합니다. (기본값은 10줄)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;조합 사용&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;tail -f -n 100 server.log&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;국룰 조합.&lt;/b&gt; &quot;현재 로그도 보고 싶고, 방금 전 상황(100줄)도 같이 보고 싶을 때&quot; 사용합니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;여러 파일 동시에&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;tail -f access.log error.log&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;멀티 모니터링.&lt;/b&gt; 여러 로그 파일을 한 화면에서 봅니다. 파일명이 헤더로 구분되어 출력됩니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2. 엔지니어를 위한 고급 스킬 (Advanced Techniques)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;단순 모니터링을 넘어, 특정 상황(로그 로테이션, 스크립트 제어 등)을 해결하는 스킬입니다.&lt;/p&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;① 로그 로테이션 대응:&lt;span&gt;&amp;nbsp;&lt;/span&gt;-F&lt;span&gt;&amp;nbsp;&lt;/span&gt;(대문자)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서버 로그는 일정 크기가 되면&lt;span&gt;&amp;nbsp;&lt;/span&gt;app.log가&lt;span&gt;&amp;nbsp;&lt;/span&gt;app.log.1로 이름이 바뀌고, 새로운&lt;span&gt;&amp;nbsp;&lt;/span&gt;app.log가 생성됩니다(Log Rotation).&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;tail -f: 파일의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Inode&lt;/b&gt;를 추적합니다. 파일명이 바뀌면(로테이션되면) 더 이상 새 로그를 보여주지 못하고 멈춥니다.&lt;/li&gt;
&lt;li&gt;tail -F: 파일의 **이름(Filename)**을 추적합니다. 파일이 사라졌다가 다시 생기면 재접속(Retry)합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;실무 팁:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;서버 로그는 언제 로테이션될지 모르므로 습관적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;소문자&lt;span&gt;&amp;nbsp;&lt;/span&gt;-f&lt;span&gt;&amp;nbsp;&lt;/span&gt;대신 대문자&lt;span&gt;&amp;nbsp;&lt;/span&gt;-F를 쓰는 것이 좋습니다.&lt;/b&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1769760284736&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tail -F /var/log/nginx/access.log&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;② 특정 프로세스가 끝날 때까지만 감시:&lt;span&gt;&amp;nbsp;&lt;/span&gt;--pid&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;배포 스크립트나 배치 작업이 도는 동안만 로그를 보고 싶을 때 유용합니다. 해당 PID가 종료되면&lt;span&gt;&amp;nbsp;&lt;/span&gt;tail도 자동으로 종료됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;상황:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;backup.sh&lt;span&gt;&amp;nbsp;&lt;/span&gt;스크립트를 백그라운드로 실행하고, 그 스크립트가 끝날 때까지만 로그를 보고 싶다.&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1769759862451&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./backup.sh &amp;amp;          # 백그라운드 실행
PID=$!                 # 방금 실행한 프로세스 ID 저장
tail -f backup.log --pid=$PID  # 해당 PID가 죽으면 tail도 같이 종료됨&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;③ 바이트 단위로 자르기:&lt;span&gt;&amp;nbsp;&lt;/span&gt;-c&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;텍스트 파일이 아닌 바이너리 파일의 뒷부분을 확인하거나, 정확한 용량만큼 데이터를 자를 때 씁니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;tail -c 10 file.txt: 파일의 마지막 10바이트만 출력.&lt;/li&gt;
&lt;li&gt;tail -c +10 file.txt: (활용도 높음)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;앞의 10바이트를 건너뛰고&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;11바이트부터 끝까지 출력.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;④ 헤더 숨기기 (깔끔하게 보기):&lt;span&gt;&amp;nbsp;&lt;/span&gt;-q&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여러 파일을&lt;span&gt;&amp;nbsp;&lt;/span&gt;tail -f로 볼 때, 파일명이 섞여 나오는 헤더(==&amp;gt; file &amp;lt;==)가 거슬린다면 숨길 수 있습니다.&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769759887501&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tail -q -f *.log&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;3. 파이프라인(|)을 활용한 &quot;필터링 &amp;amp; 가공&quot; (Pro Level)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;tail만 단독으로 쓰는 경우는 드뭅니다. 쏟아지는 로그 속에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;원하는 정보만 골라내는 능력&lt;/b&gt;이 핵심입니다.&lt;/p&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;① 실시간 에러 캐치 (tail + grep)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;로그가 너무 빨리 올라갈 때, 'ERROR'나 'Exception' 문구만 빨간색으로 보고 싶을 때 사용합니다.&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769759915583&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 'ERROR'가 포함된 줄만 실시간 출력 + 검색어 색상 강조
tail -F app.log | grep --line-buffered --color=auto &quot;ERROR&quot;

# 'DEBUG'는 제외하고(-v), 'ERROR'만 보고 싶을 때
tail -F app.log | grep -v &quot;DEBUG&quot; | grep &quot;ERROR&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심:&lt;/b&gt;&lt;span style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68 / 0.75); text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;grep&lt;span style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68 / 0.75); text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;뒤에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;--line-buffered&lt;span style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68 / 0.75); text-align: start;&quot;&gt;를 붙여야 버퍼링 없이 즉시 출력됩니다. (안 붙이면 로그가 뚝뚝 끊겨서 나옴)&lt;/span&gt; &lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;② 실시간 데이터 가공 (tail + awk)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;로그 포맷이 일정할 때(예: Nginx, Apache), 전체 줄이 아니라 **특정 컬럼(IP주소, 응답코드)**만 뽑아서 봅니다.&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769759948919&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Nginx 로그에서 맨 앞의 IP 주소($1)와 9번째 응답코드($9)만 실시간 확인
tail -F access.log | awk '{print $1, $9}'&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;③ 로그가 멈췄는지 확인 (파일 갱신 시각 확인)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;로그 내용보다&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;로그가 잘 쌓이고 있는지(서버가 살아있는지)&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;확인할 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;ls와 결합합니다.&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769759969587&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 실시간 감시가 아니라, 파일 갱신 여부를 반복 확인 (watch 명령어 활용)
watch -n 1 &quot;ls -lh /var/log/syslog&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;tail을 대체하는 모던 툴 (Bonus)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리눅스 고수들은 순정&lt;span&gt;&amp;nbsp;&lt;/span&gt;tail이 답답할 때 다음 도구들을 설치해서 씁니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;multitail&lt;/b&gt;: 화면을 분할(Split View)해서 여러 로그를 동시에 보여줍니다. (색상 강조 기능 강력)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;lnav&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Log Navigator)&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;강력 추천.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로그 파일을 SQL처럼 쿼리하거나, 자동으로 포맷을 인식해서 예쁘게 보여줍니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;less +F&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;less&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령어로 파일을 연 뒤&lt;span&gt;&amp;nbsp;&lt;/span&gt;Shift + F를 누르면&lt;span&gt;&amp;nbsp;&lt;/span&gt;tail -f&lt;span&gt;&amp;nbsp;&lt;/span&gt;모드가 됩니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;장점:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;tail은 지나간 로그를 스크롤해서 올리기 힘들지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;less는&lt;span&gt;&amp;nbsp;&lt;/span&gt;Ctrl+C로 멈추고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;화살표 키로 위로 올려서 과거 로그를 분석&lt;/b&gt;하다가 다시&lt;span&gt;&amp;nbsp;&lt;/span&gt;Shift+F로 실시간 모드로 복귀할 수 있습니다. (관리자들이 제일 사랑하는 기능)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;요약: 엔지니어의&lt;span&gt;&amp;nbsp;&lt;/span&gt;tail&lt;span&gt;&amp;nbsp;&lt;/span&gt;치트시트&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로그 로테이션이 걱정된다면? =&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;tail -F&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;여러 파일을 동시에 본다면? =&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;tail -f log1 log2&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;특정 에러만 보고 싶다면? =&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;tail -f log | grep &quot;ERROR&quot;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;지나간 로그도 보고 실시간도 보고 싶다면? =&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;less&lt;span&gt;&amp;nbsp;&lt;/span&gt;실행 후&lt;span&gt;&amp;nbsp;&lt;/span&gt;Shift + F&lt;/b&gt;&lt;span style=&quot;color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>OS/Linux</category>
      <category>grep</category>
      <category>LESS</category>
      <category>lnav</category>
      <category>multitail</category>
      <category>Shift</category>
      <category>TAIL</category>
      <category>리눅스</category>
      <category>서버</category>
      <category>유닉스</category>
      <category>파일확인</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/38</guid>
      <comments>https://neorc.tistory.com/38#entry38comment</comments>
      <pubDate>Fri, 30 Jan 2026 17:07:40 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 프로그램 시작 끝 수행 시간 출력하기</title>
      <link>https://neorc.tistory.com/37</link>
      <description>&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바에서 프로그램의 시작 및 종료 시간을 출력하고 실행 시간을 계산하는 방법은 사용하는 자바 버전에 따라 크게 두 가지로 나뉩니다. 개발자이시므로 최신 프로젝트에 적합한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Modern Java (Java 8+)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방식과 레거시 코드에서 주로 쓰이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;System.currentTimeMillis()&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방식을 구분하여 설명해 드리겠습니다.&lt;/p&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;1. Modern Java (권장: Java 8 이상)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Java 8부터 도입된&lt;span&gt;&amp;nbsp;&lt;/span&gt;java.time&lt;span&gt;&amp;nbsp;&lt;/span&gt;패키지를 사용하는 것이 가장 정확하고 코드 가독성이 좋습니다. 날짜 출력에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;LocalDateTime, 시간 차이 계산에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;Duration이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;ChronoUnit을 사용합니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;​&lt;/p&gt;
&lt;pre id=&quot;code_1764659923729&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class ExecutionTimeModern {
    public static void main(String[] args) {
        // 포맷 정의 (예: 2025-12-02 15:30:00.123)
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd HH:mm:ss.SSS&quot;);

        // 1. 시작 시간 기록 및 출력
        LocalDateTime startTime = LocalDateTime.now();
        System.out.println(&quot;프로그램 시작: &quot; + startTime.format(formatter));

        // --- 실행할 작업 (예시) ---
        doHeavyWork();
        // -----------------------

        // 2. 종료 시간 기록 및 출력
        LocalDateTime endTime = LocalDateTime.now();
        System.out.println(&quot;프로그램 종료: &quot; + endTime.format(formatter));

        // 3. 소요 시간 계산 (밀리초 단위)
        long elapsedMillis = ChronoUnit.MILLIS.between(startTime, endTime);
        System.out.println(&quot;실행 시간(ms): &quot; + elapsedMillis + &quot;ms&quot;);
    }

    private static void doHeavyWork() {
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2. Legacy 방식 (System.currentTimeMillis)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Java 7 이하 버전이나 단순한 로깅용으로 여전히 많이 사용됩니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;System.currentTimeMillis()는 1970년 1월 1일 UTC부터 흐른 시간을 밀리초(ms)로 반환합니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;​&lt;/p&gt;
&lt;pre id=&quot;code_1764659963354&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.text.SimpleDateFormat;
import java.util.Date;

public class ExecutionTimeLegacy {
    public static void main(String[] args) {
        // 포맷 정의
        SimpleDateFormat sdf = new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss.SSS&quot;);

        // 1. 시작 시간
        long start = System.currentTimeMillis();
        System.out.println(&quot;시작 시간: &quot; + sdf.format(new Date(start)));

        // --- 실행할 작업 ---
        doHeavyWork();
        // ----------------

        // 2. 종료 시간
        long end = System.currentTimeMillis();
        System.out.println(&quot;종료 시간: &quot; + sdf.format(new Date(end)));

        // 3. 차이 계산
        System.out.println(&quot;실행 시간: &quot; + (end - start) + &quot;ms&quot;);
    }
    
    private static void doHeavyWork() {
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot;&gt;
&lt;div style=&quot;background-color: oklch(0.6898 0.027 109.55 / 0.1); color: oklch(0.9296 0.007 106.53);&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); font-size: 1.62em; letter-spacing: -1px;&quot;&gt;3. 정밀 성능 측정 (System.nanoTime)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;만약 **&quot;시작/종료 시각(날짜)&quot;**이 중요한 것이 아니라, 알고리즘 성능 측정을 위한 **&quot;정확한 구간 실행 시간&quot;**이 중요하다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;System.nanoTime()을 사용해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;주의:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;nanoTime()이 반환하는 숫자는 현재 시각(날짜)과 무관한 임의의 값(CPU 클럭 등 기준)이므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;SimpleDateFormat으로 변환하여 날짜로 출력하면 안 됩니다. 실행 시간 계산(end - start)용으로만 사용하십시오.&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot;&gt;
&lt;div style=&quot;background-color: oklch(0.6898 0.027 109.55 / 0.1); color: oklch(0.9296 0.007 106.53);&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1764659994202&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;long startNano = System.nanoTime();
// 작업 실행
long endNano = System.nanoTime();

System.out.println(&quot;실행 시간(ns): &quot; + (endNano - startNano));
System.out.println(&quot;실행 시간(ms): &quot; + (endNano - startNano) / 1_000_000.0);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;요약 및 비교&lt;/h2&gt;
&lt;div style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot;&gt;
&lt;div&gt;방식용도특징정확도
&lt;table style=&quot;text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 32.0931%;&quot;&gt;&lt;b&gt;java.time (Instant/LocalDateTime)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 13.4883%;&quot;&gt;로그 기록, 비즈니스 로직&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 42.0931%;&quot;&gt;Java 8+ 표준, 가독성 좋음, 날짜/시간 연산 편리&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 12.2093%;&quot;&gt;높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 32.0931%;&quot;&gt;&lt;b&gt;System.currentTimeMillis()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 13.4883%;&quot;&gt;간단한 디버깅, 레거시 코드&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 42.0931%;&quot;&gt;사용하기 쉽지만 OS 시간 변경에 영향을 받음 (Wall-clock time)&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 12.2093%;&quot;&gt;밀리초(ms)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 32.0931%;&quot;&gt;&lt;b&gt;System.nanoTime()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 13.4883%;&quot;&gt;성능 벤치마킹, 정밀 측정&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 42.0931%;&quot;&gt;OS 시간 변경에 영향받지 않음. 날짜 출력 불가&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 12.2093%;&quot;&gt;나노초(ns)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: oklch(0.9902 0.004 106.47);&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일반적인 프로그램 시작/종료 로그를 남기시려면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;1번(Modern Java)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방식을 추천해 드립니다.&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>DateTimeFormatter</category>
      <category>java</category>
      <category>localdatetime</category>
      <category>nanoTime</category>
      <category>Time</category>
      <category>수행시간</category>
      <category>시간측정</category>
      <category>실행시간</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/37</guid>
      <comments>https://neorc.tistory.com/37#entry37comment</comments>
      <pubDate>Tue, 2 Dec 2025 16:22:10 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 프로그램 루프(Loop) 내에서 스래드 슬립(sleep)을 얼마를 주면 되고 주는 이유는?</title>
      <link>https://neorc.tistory.com/36</link>
      <description>&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로그램 반복 루프 내에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;Thread.sleep()을 주는 시간은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;루프의 목적&lt;/b&gt;에 따라 달라집니다. 단순히 정해진 값은 없으며, 반응성(Latency)과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;CPU 자원(Resource)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사이의 균형을 맞춰야 합니다.&lt;/p&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;엔지니어로서의 배경을 고려하여 시나리오별 권장 값과 그 이유를 정리해 드립니다.&lt;/p&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;1. 시나리오별 권장 시간&lt;/h2&gt;
&lt;div style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot;&gt;
&lt;div&gt;시나리오권장 시간설명
&lt;table style=&quot;text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 20.8139%;&quot;&gt;&lt;b&gt;초고속 대기 (Spin-wait)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 15.3488%;&quot;&gt;0ms&lt;span&gt;&amp;nbsp;&lt;/span&gt;~&lt;span&gt;&amp;nbsp;&lt;/span&gt;1ms&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 63.8372%;&quot;&gt;즉각적인 반응이 필요할 때(예: 게임 루프, 초단타 매매). 단,&lt;span&gt;&amp;nbsp;&lt;/span&gt;sleep(0)은 OS 스케줄러에 따라 동작이 다를 수 있어&lt;span&gt;&amp;nbsp;&lt;/span&gt;sleep(1)이 더 안전합니다&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;​.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 20.8139%;&quot;&gt;&lt;b&gt;일반적인 폴링 (Polling)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 15.3488%;&quot;&gt;100ms&lt;span&gt;&amp;nbsp;&lt;/span&gt;~&lt;span&gt;&amp;nbsp;&lt;/span&gt;500ms&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 63.8372%;&quot;&gt;DB나 파일 변경 감지 등. 100ms는 사람이 '즉시'라고 느끼는 한계 시간이므로, UX에 영향 없이 자원을 아낄 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 20.8139%;&quot;&gt;&lt;b&gt;API 호출 / 네트워크&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 15.3488%;&quot;&gt;1000ms&lt;span&gt;&amp;nbsp;&lt;/span&gt;이상&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 63.8372%;&quot;&gt;외부 서버의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Rate Limit&lt;/b&gt;(요청 제한)에 맞춰야 합니다. 너무 빠르면 IP가 차단될 수 있습니다&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;​.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 20.8139%;&quot;&gt;&lt;b&gt;UI / 애니메이션&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 15.3488%;&quot;&gt;~16ms&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 63.8372%;&quot;&gt;60 FPS(초당 60프레임)를 맞추기 위해 약 16ms(1000/60) 주기로 갱신합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: oklch(0.9902 0.004 106.47);&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2. 추가하는 이유 (핵심: 바쁜 대기 방지)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가장 큰 이유는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;CPU 점유율(Busy Waiting) 방지&lt;/b&gt;입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CPU 과열 및 배터리 소모 방지:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;sleep&lt;span&gt;&amp;nbsp;&lt;/span&gt;없이&lt;span&gt;&amp;nbsp;&lt;/span&gt;while(true)를 돌리면 해당 스레드는 CPU 코어 하나를 100% 점유하게 됩니다. 이는 노트북의 배터리를 광속으로 소모시키고 발열을 유발합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Thread.sleep(1)만 주어도 CPU 점유율은 거의 0% 가까이 떨어집니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;​&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컨텍스트 스위칭 (Context Switching):&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;sleep을 호출하면 현재 스레드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;RUNNABLE&lt;span&gt;&amp;nbsp;&lt;/span&gt;상태에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;TIMED_WAITING&lt;span&gt;&amp;nbsp;&lt;/span&gt;상태로 변합니다. 이 틈에 OS 스케줄러가 다른 스레드나 프로세스에게 CPU 자원을 할당할 수 있게 되어 전체 시스템의 멀티태스킹 성능이 보장됩니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;3. 개발자를 위한 팁 (Best Practices)&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;질문하신 분께서 자바 네트워크나 트레이딩 알고리즘을 다루시므로, 단순&lt;span&gt;&amp;nbsp;&lt;/span&gt;sleep보다 더 나은 패턴들을 추천합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ScheduledExecutorService&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;단순 무한 루프에&lt;span&gt;&amp;nbsp;&lt;/span&gt;sleep을 넣는 것보다, 자바 5부터 도입된&lt;span&gt;&amp;nbsp;&lt;/span&gt;ScheduledExecutorService를 사용하는 것이 스레드 관리와 예외 처리 면에서 훨씬 안전하고 우아한 방법입니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;​&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이벤트 기반 처리 (wait&lt;span&gt;&amp;nbsp;&lt;/span&gt;/&lt;span&gt;&amp;nbsp;&lt;/span&gt;notify):&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;특정 조건이 만족될 때만 깨어나야 한다면, 루프를 돌며 감시(Polling)하는 것보다&lt;span&gt;&amp;nbsp;&lt;/span&gt;Object.wait()와&lt;span&gt;&amp;nbsp;&lt;/span&gt;notify()를 사용하여 불필요한 CPU 사용을 원천 차단하는 것이 좋습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Java 9+&lt;span&gt;&amp;nbsp;&lt;/span&gt;Thread.onSpinWait():&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;만약 나노초 단위의 극도로 짧은 대기(Spin-lock 등)가 필요한 상황이라면&lt;span&gt;&amp;nbsp;&lt;/span&gt;sleep&lt;span&gt;&amp;nbsp;&lt;/span&gt;대신&lt;span&gt;&amp;nbsp;&lt;/span&gt;Thread.onSpinWait()&lt;span&gt;&amp;nbsp;&lt;/span&gt;힌트를 사용하여 CPU에게 &quot;잠깐 멈추라&quot;는 신호를 주는 것이 더 효율적입니다.&lt;/li&gt;
&lt;li&gt;
&lt;div style=&quot;background-color: oklch(0.6898 0.027 109.55 / 0.1); color: oklch(0.9296 0.007 106.53);&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1764660204725&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1초마다 실행 (권장) 
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); 
scheduler.scheduleAtFixedRate(() -&amp;gt; { /* 로직 */ }, 0, 1, TimeUnit.SECONDS);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: oklch(0.9902 0.004 106.47); color: oklch(0.3039 0.04 213.68); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요약하자면:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;일반적인 백그라운드 작업이라면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;100ms&lt;/b&gt;, 외부 API 통신이라면 1초 이상(또는 Rate Limit)을 기준으로 잡으시면 됩니다.&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>CPU</category>
      <category>java</category>
      <category>onSpinWait</category>
      <category>scheduleExecutorService</category>
      <category>sleep</category>
      <category>Thread</category>
      <category>루프</category>
      <category>스래드</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/36</guid>
      <comments>https://neorc.tistory.com/36#entry36comment</comments>
      <pubDate>Fri, 28 Nov 2025 15:00:30 +0900</pubDate>
    </item>
    <item>
      <title>근로소득과 사업소득 합산이 얼마이면 복식부기 대상 기준</title>
      <link>https://neorc.tistory.com/35</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;근로소득이 있어도 복식부기 의무자 판정은 사업소득의 규모에 따라서만 결정됩니다. 근로소득은 복식부기 의무자 판정 기준에 포함되지 않습니다&lt;/blockquote&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;복식부기 의무자 판정 기준&lt;/b&gt;&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;복식부기 의무자가 되는 기준은&amp;nbsp;&lt;b&gt;직전연도 사업소득 수입금액&lt;/b&gt;만을 기준으로 하며, 업종별로 다음과 같습니다.&lt;/p&gt;&lt;div style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot;&gt; 
 &lt;div&gt;
  업종 구분복식부기 의무자 기준 
  &lt;table style=&quot;text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt; 
   &lt;tbody&gt; 
    &lt;tr&gt; 
     &lt;td&gt;가군 (도소매업, 부동산매매업 등)&lt;/td&gt; 
     &lt;td&gt;3억원 이상&lt;/td&gt; 
    &lt;/tr&gt; 
    &lt;tr&gt; 
     &lt;td&gt;나군 (제조업, 음식점업, 숙박업 등)&lt;/td&gt; 
     &lt;td&gt;1억 5천만원 이상&lt;/td&gt; 
    &lt;/tr&gt; 
    &lt;tr&gt; 
     &lt;td&gt;다군 (부동산임대업, 서비스업 등)&lt;/td&gt; 
     &lt;td&gt;7천 5백만원 이상&lt;/td&gt; 
    &lt;/tr&gt; 
   &lt;/tbody&gt; 
  &lt;/table&gt; 
 &lt;/div&gt; 
 &lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt; 
 &lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;근로소득이 있는 개인사업자의 경우&lt;/b&gt;&lt;/p&gt; 
&lt;/div&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;근로소득이 5천만원이 있고 사업소득이 5천만원인 경우,&amp;nbsp;&lt;b&gt;사업소득 5천만원만&lt;/b&gt;으로 판정하므로 간편장부 대상자가 됩니다.&amp;nbsp;근로소득의 크기는 복식부기 의무자 판정에 전혀 영향을 주지 않습니다.&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;복식부기 의무자의 신고 방식&lt;/b&gt;&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;복식부기 의무자가 되면 근로소득과 사업소득을&amp;nbsp;&lt;b&gt;모두 합산&lt;/b&gt;하여 종합소득세를 신고해야 하지만, 반드시&amp;nbsp;&lt;b&gt;복식부기로만&lt;/b&gt;&amp;nbsp;신고가 가능합니다.&amp;nbsp;간편장부나 추계신고를 하는 경우 무기장가산세(산출세액의 20%)가 부과됩니다.&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;간편장부 대상자의 선택권&lt;/b&gt;&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;사업소득이 복식부기 기준 미만인 간편장부 대상자는 복식부기를 선택할 수 있으며, 이 경우&amp;nbsp;&lt;b&gt;기장세액공제&lt;/b&gt;로 산출세액의 20%(한도 100만원)를 공제받을 수 있어 일반적으로 더 유리합니다.&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전문직 사업자 예외&lt;/b&gt;&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;변호사업, 공인회계사업, 세무사업, 건축사업 등&amp;nbsp;&lt;b&gt;전문직 사업자&lt;/b&gt;는 수입금액에 관계없이 무조건 복식부기 의무자에 해당합니다.&lt;br&gt;따라서 근로소득의 크기와 관계없이,&amp;nbsp;&lt;b&gt;사업소득만&lt;/b&gt;이 업종별 기준을 초과하면 복식부기 의무자가 됩니다.&lt;/p&gt;</description>
      <category>경영정보/세무정보</category>
      <category>3.3% 소득 복식부기 기준</category>
      <category>간편장부 vs 복식부기 차이점</category>
      <category>개인사업자 복식부기 조건</category>
      <category>기장세액공제 혜택 받는법</category>
      <category>복식부기 무기장가산세 피하기</category>
      <category>복식부기 의무자 기준 2025</category>
      <category>사업소득 복식부기 계산법</category>
      <category>업종별 복식부기 의무자 판정</category>
      <category>종합소득세 복식부기 신고</category>
      <category>프리랜서 복식부기 7500만원</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/35</guid>
      <comments>https://neorc.tistory.com/35#entry35comment</comments>
      <pubDate>Thu, 29 May 2025 14:56:45 +0900</pubDate>
    </item>
    <item>
      <title>3.3% 프리랜서 소득과 사업소득 합산이 얼마정도 되면 복식부기 대상 기준</title>
      <link>https://neorc.tistory.com/34</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;복식부기 의무자 판정은 직전연도 수입금액을 기준으로 하며, 3.3% 프리랜서 소득과 사업소득을 모두 합산하여 판단합니다&lt;/blockquote&gt;
&lt;h2 id=&quot;&quot; style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;업종별 복식부기 의무자 기준&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;복식부기 의무자가 되는 수입금액 기준은 업종에 따라 다릅니다.&lt;/p&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&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; background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;3억원 이상: 복식부기 의무자&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나군 (제조업, 숙박&amp;middot;음식점업, 건설업, 운수업, 정보통신업, 금융&amp;middot;보험업 등)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1억 5천만원 이상: 복식부기 의무자&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다군 (부동산 임대업, 전문&amp;middot;과학&amp;middot;기술 서비스업, 교육서비스업, 예술&amp;middot;스포츠업 등)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;7천 5백만원 이상: 복식부기 의무자&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;&quot; style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3.3% 프리랜서의 복식부기 판정&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;대부분의 3.3% 프리랜서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다군&lt;/b&gt;에 해당하므로, 직전연도 수입금액이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;7천 5백만원을 초과&lt;/b&gt;하면 복식부기 의무자가 됩니다&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 2025년 종합소득세 신고 시에는 2024년 수입금액을 기준으로 판정하며, 2024년에 3.3% 소득과 기타 사업소득을 합쳐서 7천 5백만원을 초과했다면 복식부기로 신고해야 합니다.&lt;/p&gt;
&lt;h2 id=&quot;&quot; style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;특별한 경우들&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&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; background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;당해연도에 신규로 사업을 개시한 경우에는 간편장부 대상자가 됩니다.&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&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; background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의료업, 변호사업, 건축사업, 회계사업, 세무사업 등 전문직은 수입금액에 관계없이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;무조건 복식부기 의무자&lt;/b&gt;입니다.&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&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; background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복식부기 의무 판정은 직전연도 영위 업종의 기준을 적용합니다. 예를 들어, 작년에 다군 업종(기준 7천 5백만원)을 영위했다면, 올해 나군 업종으로 변경해도 작년 기준인 7천 5백만원으로 판정합니다&lt;span&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 3.3% 프리랜서의 경우 일반적으로 직전연도 총 수입금액이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;7천 5백만원을 초과&lt;/b&gt;하면 복식부기 의무자가 되며,&lt;/p&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 경우 정식 장부 작성과 재무상태표, 손익계산서 제출 의무가 발생합니다.&lt;/p&gt;
&lt;p style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>경영정보/세무정보</category>
      <category>3.3% 프리랜서 복식부기</category>
      <category>간편장부 vs 복식부기</category>
      <category>기장세액공제 혜택</category>
      <category>무기장가산세 부과</category>
      <category>복식부기 의무자 기준</category>
      <category>사업소득 합산 계산</category>
      <category>업종별 복식부기 기준</category>
      <category>전문직 복식부기 의무</category>
      <category>종합소득세 신고방법</category>
      <category>직전연도 수입금액 기준</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/34</guid>
      <comments>https://neorc.tistory.com/34#entry34comment</comments>
      <pubDate>Thu, 29 May 2025 14:49:55 +0900</pubDate>
    </item>
    <item>
      <title>소프트웨어 개발 및 공급 복식부기의무자 기준</title>
      <link>https://neorc.tistory.com/33</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;★ 예상치 못한 세무서 연락, 혹시 당신도 놓치고 있나요?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;소프트웨어 개발 복식부기의무자 기준은 무엇일까요? 실제 현장에서 자주 듣는 질문이지만, 막상 정확한 기준을 명확히 아는 분은 드뭅니다.&amp;nbsp; &amp;nbsp;&amp;ldquo;내가 복식부기의무자인지, 간편장부 대상자인지 헷갈린다&amp;rdquo;는 개발자분들을 많이 만났는데요. 이번 글에서는 소프트웨어 개발 업종의 복식부기의무자 기준과 함께 실제 사례, 그리고 많은 분들이 오해하는 부분까지 꼼꼼하게 정리해드리겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;★ 알면 쉽고 모르면 어려운 복식부기의무자의 모든 것&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  복식부기의무자 기준, 정확히 알고 계신가요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국세청 최신 자료에 따르면 2024년 기준으로 복식부기의무자 기준은 업종별로 다르게 적용됩니다. 소프트웨어 개발 및 공급업의 경우 서비스업에 해당하므로, 직전연도 수입금액이 1억 5천만원 이상이면 당연히 복식부기 적용 대상이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &amp;lsquo;수입금액&amp;rsquo;이란 부가가치세 포함 매출액 전체를 의미하며, 단순히 순이익이나 세전이익이 아닙니다. 예를 들어, 2024년에 프로젝트 3건을 수주해서 총 매출이 1억 6천만 원이었다면, 2024년에는 복식부기의무자로 분류되어 복식부기 장부를 작성해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 많은 분들이 착각하시는 부분이 있어요. &quot;우리 회사는 매출이 1억 5천만원이 안 되니까 상관없다&quot;고 생각하시는데, 이는 잘못된 판단입니다. 복식부기의무자 기준에는 '당연적용'과 '임의적용'이 있기 때문이에요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  실제 경험으로 배운 중요한 포인트들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 매출이 기준에 못 미쳤지만 급성장하면서 어느새 복식부기의무자 기준을 넘어서게 되었습니다. 그런데 이 사실을 미처 파악하지 못하고 계속 간편장부로 신고를 했던 거죠. 다행히 세무서에서 연락을 해주어서 알게 되었지만, 만약 그대로 놔뒀다면 가산세까지 물어야 할 상황이었어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 소프트웨어 개발업은 프로젝트 단위로 큰 금액이 한 번에 들어오는 경우가 많습니다. 예를 들어 대기업의 시스템 구축 프로젝트를 수주하면 단숨에 몇억원의 매출이 발생할 수 있거든요. 이런 특성 때문에 예상보다 빨리 복식부기의무자 기준에 도달할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  복식부기의무자가 되면 달라지는 것들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복식부기의무자가 되면 단순히 장부 작성 방법만 바뀌는 것이 아닙니다. 세무신고 방식부터 필요한 서류, 심지어 세율까지 달라질 수 있어요. 가장 중요한 변화는 장부 작성 의무인데, 기존의 간편장부와 달리 재무상태표와 손익계산서를 작성해야 하고, 모든 거래를 차변과 대변으로 기록해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 어려워 보이지만, 실제로 해보면 회사의 재무상태를 더 정확하게 파악할 수 있어서 경영에도 도움이 됩니다. 저희 회사도 복식부기로 전환한 후 월별 손익 분석이 훨씬 정확해졌고, 이를 바탕으로 더 나은 경영 판단을 할 수 있게 되었어요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;⚠️ 놓치기 쉬운 주의사항들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 컨설팅했던 한 모바일 앱 개발 회사는 연 매출이 2억원 정도 되었는데, 복식부기의무자 기준을 모르고 계속 간편장부로 신고하다가 세무조사를 받게 되었습니다. 결국 3년치 가산세를 물어야 했고, 추가로 전문가의 도움을 받아 장부를 재작성하는 비용까지 들었어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 일을 방지하려면 매년 연말에 당해연도 수입금액을 꼼꼼히 점검해보시기 바랍니다. 특히 소프트웨어 업계는 매출 변동이 큰 편이라서 더욱 주의가 필요합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  해결방법과 실무 팁&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[복식부기 전환 체크리스트] 복식부기 전환 시 확인해야 할 주요 항목들&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;연간 수입금액 모니터링 &amp;rarr; 매월 누적 매출 확인&lt;/li&gt;
&lt;li&gt;회계프로그램 도입 검토 &amp;rarr; 복식부기 지원 소프트웨어 선택&lt;/li&gt;
&lt;li&gt;세무사 상담 &amp;rarr; 전문가와 미리 상담받기&lt;/li&gt;
&lt;li&gt;직원 교육 &amp;rarr; 회계 담당자 교육 실시&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 중요한 것은 미리 준비하는 것입니다. 복식부기의무자 기준에 도달하기 전에 미리 회계 시스템을 구축해두면 전환 과정에서 발생할 수 있는 혼란을 최소화할 수 있어요.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;★ 미리 준비하면 기회가 됩니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복식부기의무자 기준을 정확히 알고 미리 준비하면 오히려 회사 운영에 도움이 됩니다. 복식부기를 통해 회사의 재무상태를 정확히 파악할 수 있고, 이는 향후 투자 유치나 대출 신청 시에도 유리하게 작용해요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 제 경험을 바탕으로 소프트웨어 개발 및 공급업체의 복식부기의무자 기준에 대해 자세히 알려드렸습니다. 혹시 여러분의 회사도 기준에 해당한다면 미리 준비하시길 바랍니다. 세무는 귀찮고 복잡하지만, 제대로 알고 준비하면 든든한 경영의 밑바탕이 될 수 있거든요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발에만 집중하고 싶은 마음은 저도 잘 압니다. 하지만 성공적인 사업을 위해서는 이런 기본적인 세무 지식도 필수라는 것을 꼭 기억해주세요.&lt;/p&gt;</description>
      <category>경영정보/세무정보</category>
      <category>it서비스업 당연적용 기준금액</category>
      <category>it회사 매출 1억5천만원 세무신고</category>
      <category>개발자 사업자 복식부기 의무사항</category>
      <category>개발회사 재무제표 작성 방법</category>
      <category>복식부기 간편장부 차이점 비교</category>
      <category>복식부기 선택신고 혜택 분석</category>
      <category>소프트웨어 개발업 복식부기 신고방법</category>
      <category>소프트웨어 공급업 세무신고 주의점</category>
      <category>소프트웨어 회사 세무조사 대비법</category>
      <category>앱개발업체 장부작성 의무 확인</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/33</guid>
      <comments>https://neorc.tistory.com/33#entry33comment</comments>
      <pubDate>Tue, 27 May 2025 12:17:00 +0900</pubDate>
    </item>
    <item>
      <title>[Java] OutputStreamWriter를 사용할 때 한글이 깨지는 현상 해결 방</title>
      <link>https://neorc.tistory.com/32</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;OutputStreamWriter를 사용할 때 한글이 깨지는 이유는 문자 인코딩을 명시하지 않고 기본 인코딩을 사용할 경우&lt;br /&gt;, 시스템 환경에 따라 UTF-8이 아닌 다른 문자셋(예:EUC-KR, ISO-8859-1)이 사용되기 때문입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 문제 상황 예시 (깨지는 코드)&lt;/p&gt;
&lt;pre id=&quot;code_1747706351537&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;OutputStream os = connection.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(os); // ❌ 인코딩 미지정
writer.write(&quot;홍길동&quot;);
writer.flush();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우, OutputStreamWriter는 시스템 기본 문자셋을 사용합니다. 시스템이 UTF-8이 아닐 경우 한글이 깨질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 해결 방법: 명시적으로 UTF-8 인코딩 지정&lt;/p&gt;
&lt;pre id=&quot;code_1747706376519&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;OutputStream os = connection.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(os, &quot;UTF-8&quot;); // ✅ 인코딩 지정
writer.write(&quot;홍길동&quot;);
writer.flush();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는 BufferedWriter를 함께 쓰면 더 안정적이고 효율적으로 데이터를 보낼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1747706394238&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), &quot;UTF-8&quot;));
bw.write(&quot;홍길동&quot;);
bw.flush();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 반드시 같이 설정해야 하는 부분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;HTTP 헤더에도 인코딩 지정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1747706470888&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;connection.setRequestProperty(&quot;Content-Type&quot;, &quot;application/json; charset=UTF-8&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서버가 UTF-8로 응답하지 않으면, 응답도 수동 디코딩 필요&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1747706491268&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;new InputStreamReader(conn.getInputStream(), &quot;UTF-8&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 결론&lt;/p&gt;
&lt;p data-end=&quot;1160&quot; data-start=&quot;1113&quot; data-ke-size=&quot;size16&quot;&gt;OutputStreamWriter를 사용할 땐 항상 &lt;b&gt;두 가지&lt;/b&gt;를 체크하세요:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1211&quot; data-start=&quot;1162&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1181&quot; data-start=&quot;1162&quot;&gt;인코딩 &quot;UTF-8&quot;을 명시&lt;/li&gt;
&lt;li data-end=&quot;1211&quot; data-start=&quot;1182&quot;&gt;HTTP 헤더에 charset=UTF-8 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1294&quot; data-start=&quot;1213&quot; data-ke-size=&quot;size16&quot;&gt;그렇지 않으면 환경에 따라 한글이 깨질 수 있습니다. 특히 &lt;b&gt;윈도우 환경에서 개발하고 리눅스 서버에 배포&lt;/b&gt;할 때 이런 문제가 자주 발생합니다.&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>#Java</category>
      <category>https통신</category>
      <category>OutputStreamWriter</category>
      <category>outputstreamwriter utf8</category>
      <category>utf8인코딩</category>
      <category>자바api연동</category>
      <category>자바json전송</category>
      <category>자바네트워크</category>
      <category>자바한글깨짐</category>
      <category>한글인코딩문제</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/32</guid>
      <comments>https://neorc.tistory.com/32#entry32comment</comments>
      <pubDate>Tue, 20 May 2025 11:04:39 +0900</pubDate>
    </item>
    <item>
      <title>[Java] HttpsURLConnection에서 한글 깨짐 현상 해결 방법</title>
      <link>https://neorc.tistory.com/31</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Java로 HTTPS 요청을 보내다 보면, JSON이나 텍스트 데이터를 주고받을 때 한글이 깨지는 문제를 종종 경험하게 됩니다. 저도 초기에 API를 연동하면서 &quot;홍길동&quot;이라는 문자열이 서버에 도착했을 때 &amp;igrave;&amp;acute;&amp;circ;&amp;ecirc;&amp;cedil;&amp;deg;&amp;igrave; 처럼 깨지는 걸 보고 당황했던 기억이 납니다.&lt;br /&gt;그렇다면 이 현상은 왜 생기며, 어떻게 해결할 수 있을까요?&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;354&quot; data-start=&quot;339&quot; data-ke-size=&quot;size26&quot;&gt;한글 깨짐 원인은?&lt;/h2&gt;
&lt;p data-end=&quot;471&quot; data-start=&quot;355&quot; data-ke-size=&quot;size16&quot;&gt;가장 큰 이유는 &lt;b&gt;인코딩 설정 누락&lt;/b&gt;입니다.&lt;br /&gt;Java에서는 기본적으로 ISO-8859-1 인코딩을 사용하는 경우가 있기 때문에, 명시적으로 UTF-8을 지정하지 않으면 한글이 깨질 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;561&quot; data-start=&quot;473&quot; data-ke-size=&quot;size16&quot;&gt;또한 서버와 클라이언트 간의 통신에서는 &lt;b&gt;요청(Request)과 응답(Response)&lt;/b&gt; 모두에서 인코딩이 중요합니다. 하나라도 빠지면 문제가 발생합니다.&lt;/p&gt;
&lt;p data-end=&quot;561&quot; data-start=&quot;473&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;607&quot; data-start=&quot;568&quot; data-ke-size=&quot;size26&quot;&gt;해결 방법 ①: Content-Type 헤더에 charset 설정&lt;/h2&gt;
&lt;p data-end=&quot;657&quot; data-start=&quot;609&quot; data-ke-size=&quot;size16&quot;&gt;요청을 보낼 때, 아래와 같이 charset=UTF-8을 반드시 포함해줘야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1747705896086&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;conn.setRequestProperty(&quot;Content-Type&quot;, &quot;application/json; charset=UTF-8&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 이 정보를 기준으로 데이터를 UTF-8로 해석하게 됩니다.&lt;/p&gt;
&lt;h2 data-end=&quot;821&quot; data-start=&quot;791&quot; data-ke-size=&quot;size26&quot;&gt;해결 방법 ②: 데이터 전송 시 UTF-8 인코딩&lt;/h2&gt;
&lt;p data-end=&quot;865&quot; data-start=&quot;823&quot; data-ke-size=&quot;size16&quot;&gt;OutputStream에 데이터를 쓸 때도 UTF-8로 변환해 줘야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1747705926920&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String jsonInput = &quot;{\&quot;name\&quot;:\&quot;홍길동\&quot;}&quot;;
try (OutputStream os = conn.getOutputStream()) {
    byte[] input = jsonInput.getBytes(&quot;UTF-8&quot;);
    os.write(input, 0, input.length);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-end=&quot;1092&quot; data-start=&quot;1063&quot; data-ke-size=&quot;size26&quot;&gt;해결 방법 ③: 응답 읽기 시 UTF-8 디코딩&lt;/h2&gt;
&lt;p data-end=&quot;1146&quot; data-start=&quot;1094&quot; data-ke-size=&quot;size16&quot;&gt;서버로부터 응답을 받을 때도 InputStreamReader에 UTF-8을 지정해 주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1747705977474&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try (BufferedReader br = new BufferedReader(
    new InputStreamReader(conn.getInputStream(), &quot;UTF-8&quot;))) {
    StringBuilder response = new StringBuilder();
    String line;
    while ((line = br.readLine()) != null) {
        response.append(line.trim());
    }
    System.out.println(&quot;Response: &quot; + response);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1499&quot; data-start=&quot;1480&quot; data-ke-size=&quot;size26&quot;&gt;실제 코드 예제 (전체 흐름)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1747706000630&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;URL url = new URL(&quot;https://example.com/api&quot;);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod(&quot;POST&quot;);
conn.setDoOutput(true);
conn.setRequestProperty(&quot;Content-Type&quot;, &quot;application/json; charset=UTF-8&quot;);
conn.setRequestProperty(&quot;Accept&quot;, &quot;application/json&quot;);

String jsonInput = &quot;{\&quot;name\&quot;:\&quot;홍길동\&quot;}&quot;;
try (OutputStream os = conn.getOutputStream()) {
    byte[] input = jsonInput.getBytes(&quot;UTF-8&quot;);
    os.write(input, 0, input.length);
}

try (BufferedReader br = new BufferedReader(
    new InputStreamReader(conn.getInputStream(), &quot;UTF-8&quot;))) {
    StringBuilder response = new StringBuilder();
    String line;
    while ((line = br.readLine()) != null) {
        response.append(line.trim());
    }
    System.out.println(&quot;Response: &quot; + response);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2385&quot; data-start=&quot;2322&quot; data-ke-size=&quot;size16&quot;&gt;HttpsURLConnection에서 한글이 깨질 땐 &lt;b&gt;항상 UTF-8 인코딩 설정을 두 번&lt;/b&gt; 확인하세요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2468&quot; data-start=&quot;2387&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2418&quot; data-start=&quot;2387&quot;&gt;요청 헤더에 charset=UTF-8 포함하기&lt;/li&gt;
&lt;li data-end=&quot;2468&quot; data-start=&quot;2419&quot;&gt;OutputStream과 InputStreamReader에 UTF-8 명시하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2512&quot; data-start=&quot;2470&quot; data-ke-size=&quot;size16&quot;&gt;이 기본적인 원칙만 잘 지키면, 한글 깨짐 없이 안정적인 통신이 가능합니다!&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>httpsurlconnection</category>
      <category>java</category>
      <category>JAVAAPI</category>
      <category>java네트워크</category>
      <category>utf8</category>
      <category>개발자팁</category>
      <category>자바개발팁</category>
      <category>자바한글인코딩</category>
      <category>코딩문제해결</category>
      <category>한글깨짐</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/31</guid>
      <comments>https://neorc.tistory.com/31#entry31comment</comments>
      <pubDate>Tue, 20 May 2025 10:54:21 +0900</pubDate>
    </item>
    <item>
      <title>[Java] HttpsURLConnection을 사용할 때 한글이 깨지는 현상</title>
      <link>https://neorc.tistory.com/30</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Java에서 HttpsURLConnection 을 사용할 때 한글이 깨지는 현상은 주로 요청(Request) 또는 응답(Response)에서 인코딩 설정이 올바르지 않을 때 발생합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;165&quot; data-start=&quot;144&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;✅&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 원인: 인코딩 설정 누락&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;370&quot; data-start=&quot;167&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;229&quot; data-start=&quot;167&quot;&gt;서버에 데이터를 보낼 때 (OutputStream) &amp;rarr; UTF-8로 인코딩하지 않으면 한글이 깨짐&lt;/li&gt;
&lt;li data-end=&quot;296&quot; data-start=&quot;230&quot;&gt;서버에서 응답 받을 때 (InputStreamReader) &amp;rarr; UTF-8로 디코딩하지 않으면 한글이 깨짐&lt;/li&gt;
&lt;li data-end=&quot;370&quot; data-start=&quot;297&quot;&gt;또한 Content-Type 헤더에 charset=utf-8 설정이 빠져있으면, 서버가 잘못된 문자셋으로 해석할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;390&quot; data-start=&quot;377&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;✅&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 해결 방법&lt;/p&gt;
&lt;p data-end=&quot;427&quot; data-start=&quot;392&quot; data-ke-size=&quot;size16&quot;&gt;아래 코드를 참고해서 인코딩 관련 설정을 &lt;b&gt;추가&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1747705511210&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;URL url = new URL(&quot;https://example.com/api&quot;);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod(&quot;POST&quot;);
conn.setDoOutput(true);

// ⚠️ 한글 깨짐 방지를 위한 필수 설정
conn.setRequestProperty(&quot;Content-Type&quot;, &quot;application/json; charset=UTF-8&quot;);
conn.setRequestProperty(&quot;Accept&quot;, &quot;application/json&quot;);

// 요청 본문 전송 시 UTF-8 인코딩
String jsonInput = &quot;{\&quot;name\&quot;:\&quot;홍길동\&quot;}&quot;;
try (OutputStream os = conn.getOutputStream()) {
    byte[] input = jsonInput.getBytes(&quot;UTF-8&quot;);
    os.write(input, 0, input.length);
}

// 응답 읽기 시에도 UTF-8 디코딩
try (BufferedReader br = new BufferedReader(
        new InputStreamReader(conn.getInputStream(), &quot;UTF-8&quot;))) {
    StringBuilder response = new StringBuilder();
    String line;
    while ((line = br.readLine()) != null) {
        response.append(line.trim());
    }
    System.out.println(&quot;Response: &quot; + response);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1331&quot; data-start=&quot;1319&quot; data-ke-size=&quot;size16&quot;&gt;✅ 추가 팁&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1503&quot; data-start=&quot;1333&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1398&quot; data-start=&quot;1333&quot;&gt;서버가 응답 헤더에 charset을 설정하지 않는 경우, 클라이언트에서 강제로 UTF-8로 읽어야 합니다.&lt;/li&gt;
&lt;li data-end=&quot;1503&quot; data-start=&quot;1399&quot;&gt;혹시 application/x-www-form-urlencoded 방식이라면, URLEncoder.encode(&quot;홍길동&quot;, &quot;UTF-8&quot;)처럼 한글 값을 직접 인코딩해 주세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1518&quot; data-start=&quot;1510&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;✅&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 결론&lt;/p&gt;
&lt;p data-end=&quot;1723&quot; data-start=&quot;1520&quot; data-ke-size=&quot;size16&quot;&gt;HttpsURLConnection에서 한글이 깨지는 문제는 대부분 &lt;b&gt;UTF-8 인코딩/디코딩 누락&lt;/b&gt; 때문입니다.&lt;br /&gt;&lt;b&gt;setRequestProperty(&quot;Content-Type&quot;, &quot;application/json; charset=UTF-8&quot;)&lt;/b&gt; 설정과&lt;br /&gt;&lt;b&gt;InputStreamReader(..., &quot;UTF-8&quot;)&lt;/b&gt; 를 꼭 확인!&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>httpsurlconnection</category>
      <category>java</category>
      <category>JAVAAPI</category>
      <category>java네트워크</category>
      <category>utf8</category>
      <category>개발자팁</category>
      <category>자바개발팁</category>
      <category>자바한글인코딩</category>
      <category>코딩문제해결</category>
      <category>한글깨짐</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/30</guid>
      <comments>https://neorc.tistory.com/30#entry30comment</comments>
      <pubDate>Tue, 20 May 2025 10:50:20 +0900</pubDate>
    </item>
    <item>
      <title>[Java]Java에서 ArrayList&amp;lt;String&amp;gt; 타입을 병합, Merge 하는 방법</title>
      <link>https://neorc.tistory.com/29</link>
      <description>&lt;blockquote data-end=&quot;71&quot; data-start=&quot;0&quot; data-ke-style=&quot;style3&quot;&gt;Java에서 ArrayList&amp;lt;String&amp;gt; 타입을 병합하는 방법은 여러 가지가 있습니다. 대표적인 방법&lt;/blockquote&gt;
&lt;p data-end=&quot;106&quot; data-start=&quot;73&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;106&quot; data-start=&quot;73&quot; data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;1. addAll() 메서드 사용하기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1747277308640&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.ArrayList;
import java.util.Arrays;

public class ArrayListMergeExample {
    public static void main(String[] args) {
        ArrayList&amp;lt;String&amp;gt; list1 = new ArrayList&amp;lt;&amp;gt;(Arrays.asList(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;));
        ArrayList&amp;lt;String&amp;gt; list2 = new ArrayList&amp;lt;&amp;gt;(Arrays.asList(&quot;D&quot;, &quot;E&quot;, &quot;F&quot;));

        list1.addAll(list2); // list1에 list2의 모든 요소 추가

        System.out.println(&quot;Merged List: &quot; + list1);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;2. Stream을 사용한 병합 (Java 8 이상)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1747277393090&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ArrayListMergeStream {
    public static void main(String[] args) {
        ArrayList&amp;lt;String&amp;gt; list1 = new ArrayList&amp;lt;&amp;gt;(Arrays.asList(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;));
        ArrayList&amp;lt;String&amp;gt; list2 = new ArrayList&amp;lt;&amp;gt;(Arrays.asList(&quot;D&quot;, &quot;E&quot;, &quot;F&quot;));

        List&amp;lt;String&amp;gt; mergedList = Stream.concat(list1.stream(), list2.stream())
                                        .collect(Collectors.toList());

        System.out.println(&quot;Merged List: &quot; + mergedList);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;3. for 루프를 사용한 병합&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1747277406484&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.ArrayList;
import java.util.Arrays;

public class ArrayListMergeForLoop {
    public static void main(String[] args) {
        ArrayList&amp;lt;String&amp;gt; list1 = new ArrayList&amp;lt;&amp;gt;(Arrays.asList(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;));
        ArrayList&amp;lt;String&amp;gt; list2 = new ArrayList&amp;lt;&amp;gt;(Arrays.asList(&quot;D&quot;, &quot;E&quot;, &quot;F&quot;));

        for (String item : list2) {
            list1.add(item);
        }

        System.out.println(&quot;Merged List: &quot; + list1);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중에서 &lt;b&gt;Java 8 이상&lt;/b&gt;이라면 Stream 방식을 권장합니다.&lt;br /&gt;가독성이 좋고, 병렬처리에도 유리합니다.  &lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>arrayList</category>
      <category>java</category>
      <category>Java8</category>
      <category>javaaddall</category>
      <category>javalistmerge</category>
      <category>javastream</category>
      <category>streamconcat</category>
      <category>개발자팁</category>
      <category>자바리스트</category>
      <category>자바스트림</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/29</guid>
      <comments>https://neorc.tistory.com/29#entry29comment</comments>
      <pubDate>Thu, 15 May 2025 11:53:27 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 자바 1.8 에서 https SSL, TLS 연결 및 응답 소스</title>
      <link>https://neorc.tistory.com/28</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;자바 1.8 환경에서 HTTPS로 연결하고 응답을 받아오는 가장 기본적인 코드를 아래에 소개합니다. 이 코드는 표준 라이브러리만 사용하며, 외부 라이브러리 없이 HTTPS 요청과 응답을 처리할 수 있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Hostname 검증 무시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 사설 인증서 무시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. TLSv1.2 사용 (Java 8.0 이상)&lt;/p&gt;
&lt;pre id=&quot;code_1746677112131&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import java.security.cert.X509Certificate;

public class SslPostRequest {
    public static void main(String[] args) {
        String httpsUrl = &quot;https://example.com/api/test&quot;;
        String jsonInput = &quot;{\&quot;key\&quot;: \&quot;value\&quot;}&quot;;

        try {
            // 사설 인증서 무시하는 TrustManager
            TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {}
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {}
                    public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
                }
            };

            // SSL 설정
            SSLContext sslContext = SSLContext.getInstance(&quot;TLSv1.2&quot;);
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            // 호스트명 검증 무시
            HttpURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

            URL url = new URL(httpsUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setSSLSocketFactory(sslSocketFactory);
            connection.setRequestMethod(&quot;POST&quot;);
            connection.setRequestProperty(&quot;Content-Type&quot;, &quot;application/json; utf-8&quot;);
            connection.setRequestProperty(&quot;Accept&quot;, &quot;application/json&quot;);
            connection.setDoOutput(true);

            try (OutputStream os = connection.getOutputStream()) {
                byte[] input = jsonInput.getBytes(&quot;utf-8&quot;);
                os.write(input, 0, input.length);
            }

            int responseCode = connection.getResponseCode();
            System.out.println(&quot;Response Code: &quot; + responseCode);

            try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), &quot;utf-8&quot;))) {
                StringBuilder response = new StringBuilder();
                String responseLine;
                while ((responseLine = br.readLine()) != null) {
                    response.append(responseLine.trim());
                }
                System.out.println(&quot;Response: &quot; + response.toString());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>https 연결</category>
      <category>https 인증</category>
      <category>httpsurlconnection</category>
      <category>Java 1.8</category>
      <category>java https</category>
      <category>REST API</category>
      <category>ssl</category>
      <category>tls</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/28</guid>
      <comments>https://neorc.tistory.com/28#entry28comment</comments>
      <pubDate>Thu, 8 May 2025 13:09:52 +0900</pubDate>
    </item>
    <item>
      <title>[Java] setConnectTimeout, setReadTimeout 타임 설정은 몇초가 좋을까?</title>
      <link>https://neorc.tistory.com/27</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Java에서&amp;nbsp;setConnectTimeout과&amp;nbsp;setReadTimeout&amp;nbsp;값을&amp;nbsp;얼마로&amp;nbsp;설정하는&amp;nbsp;것이&amp;nbsp;좋은지&amp;nbsp;고민하는&amp;nbsp;분들이&amp;nbsp;많습니다.&amp;nbsp;실제로&amp;nbsp;이&amp;nbsp;두&amp;nbsp;값은&amp;nbsp;애플리케이션의&amp;nbsp;특성,&amp;nbsp;네트워크&amp;nbsp;환경,&amp;nbsp;서버의&amp;nbsp;응답&amp;nbsp;속도에&amp;nbsp;따라&amp;nbsp;다르게&amp;nbsp;설정해야&amp;nbsp;하지만,&amp;nbsp;일반적으로&amp;nbsp;권장되는&amp;nbsp;기준과&amp;nbsp;실무&amp;nbsp;경험을&amp;nbsp;바탕으로&amp;nbsp;적절한&amp;nbsp;값을&amp;nbsp;제안할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;처음&amp;nbsp;외부&amp;nbsp;API나&amp;nbsp;서버와&amp;nbsp;통신하는&amp;nbsp;Java&amp;nbsp;코드를&amp;nbsp;작성할&amp;nbsp;때,&amp;nbsp;setConnectTimeout과&amp;nbsp;setReadTimeout의&amp;nbsp;값을&amp;nbsp;어떻게&amp;nbsp;정해야&amp;nbsp;할지&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막막했던&amp;nbsp;경험,&amp;nbsp;다들&amp;nbsp;한&amp;nbsp;번쯤&amp;nbsp;있으시죠?&amp;nbsp;저&amp;nbsp;역시&amp;nbsp;여러&amp;nbsp;프로젝트를&amp;nbsp;거치며&amp;nbsp;다양한&amp;nbsp;상황을&amp;nbsp;겪었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무&amp;nbsp;짧게&amp;nbsp;설정하면&amp;nbsp;정상적인&amp;nbsp;요청도&amp;nbsp;실패하고,&amp;nbsp;너무&amp;nbsp;길게&amp;nbsp;주면&amp;nbsp;장애&amp;nbsp;감지가&amp;nbsp;늦어져&amp;nbsp;전체&amp;nbsp;서비스에&amp;nbsp;영향을&amp;nbsp;줄&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면,&amp;nbsp;실제로&amp;nbsp;어느&amp;nbsp;정도가&amp;nbsp;&quot;적당한&quot;&amp;nbsp;값일까요? &lt;br /&gt;&lt;br /&gt;&lt;b&gt;1.&amp;nbsp;setConnectTimeout,&amp;nbsp;setReadTimeout의&amp;nbsp;의미&lt;/b&gt; &lt;br /&gt;setConnectTimeout:&amp;nbsp;서버와의&amp;nbsp;연결을&amp;nbsp;시도할&amp;nbsp;때&amp;nbsp;최대&amp;nbsp;대기&amp;nbsp;시간(밀리초&amp;nbsp;단위)입니다.&amp;nbsp;이&amp;nbsp;시간이&amp;nbsp;지나도&amp;nbsp;연결이&amp;nbsp;되지&amp;nbsp;않으면&amp;nbsp;예외가&amp;nbsp;발생합니다. &lt;br /&gt;&lt;br /&gt;setReadTimeout:&amp;nbsp;연결이&amp;nbsp;성립된&amp;nbsp;후,&amp;nbsp;데이터를&amp;nbsp;읽을&amp;nbsp;때&amp;nbsp;최대&amp;nbsp;대기&amp;nbsp;시간(밀리초&amp;nbsp;단위)입니다.&amp;nbsp;이&amp;nbsp;시간이&amp;nbsp;지나도&amp;nbsp;데이터가&amp;nbsp;도착하지&amp;nbsp;않으면&amp;nbsp;예외가&amp;nbsp;발생합니다. &lt;br /&gt;&lt;br /&gt;둘&amp;nbsp;다&amp;nbsp;0으로&amp;nbsp;설정하면&amp;nbsp;&quot;무한&amp;nbsp;대기&quot;가&amp;nbsp;되니,&amp;nbsp;반드시&amp;nbsp;적절한&amp;nbsp;값을&amp;nbsp;지정해야&amp;nbsp;합니다. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.&amp;nbsp;실무에서&amp;nbsp;많이&amp;nbsp;쓰는&amp;nbsp;권장값&lt;/b&gt; &lt;br /&gt;5초(5000ms):&amp;nbsp;가장&amp;nbsp;보편적으로&amp;nbsp;많이&amp;nbsp;쓰이는&amp;nbsp;값입니다.&amp;nbsp;국내외&amp;nbsp;다양한&amp;nbsp;개발자&amp;nbsp;커뮤니티와&amp;nbsp;공식&amp;nbsp;문서,&amp;nbsp;실무&amp;nbsp;경험을&amp;nbsp;종합해&amp;nbsp;보면,&amp;nbsp;5초는&amp;nbsp;대부분의&amp;nbsp;네트워크&amp;nbsp;환경에서&amp;nbsp;무난하게&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;기준선입니다. &lt;br /&gt;&lt;br /&gt;10~15초:&amp;nbsp;외부&amp;nbsp;네트워크이거나,&amp;nbsp;상대&amp;nbsp;서버가&amp;nbsp;느릴&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;환경에서는&amp;nbsp;10초,&amp;nbsp;길게는&amp;nbsp;15초까지도&amp;nbsp;설정합니다.&amp;nbsp;하지만&amp;nbsp;20초&amp;nbsp;이상은&amp;nbsp;사용자가&amp;nbsp;기다리기&amp;nbsp;힘들어하는&amp;nbsp;구간이기&amp;nbsp;때문에&amp;nbsp;권장하지&amp;nbsp;않습니다. &lt;br /&gt;&lt;br /&gt;내부망:&amp;nbsp;내부&amp;nbsp;서비스&amp;nbsp;간&amp;nbsp;통신이라면&amp;nbsp;2~5초로&amp;nbsp;더&amp;nbsp;짧게&amp;nbsp;잡기도&amp;nbsp;합니다. &lt;br /&gt;&lt;br /&gt;실제&amp;nbsp;코드&amp;nbsp;예시&amp;nbsp;(Apache&amp;nbsp;HttpClient&amp;nbsp;기준)&lt;/p&gt;
&lt;pre id=&quot;code_1745568037331&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RequestConfig requestConfig = RequestConfig.custom()
    .setConnectTimeout(5000) // 연결 타임아웃 5초
    .setSocketTimeout(5000)  // 읽기 타임아웃 5초
    .build();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게&amp;nbsp;5초로&amp;nbsp;설정하는&amp;nbsp;것이&amp;nbsp;가장&amp;nbsp;일반적입니다. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;3.&amp;nbsp;상황별로&amp;nbsp;달라질&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;기준&lt;/b&gt; &lt;br /&gt;대용량&amp;nbsp;파일&amp;nbsp;다운로드,&amp;nbsp;스트리밍:&amp;nbsp;데이터&amp;nbsp;전송이&amp;nbsp;오래&amp;nbsp;걸릴&amp;nbsp;수&amp;nbsp;있으니,&amp;nbsp;readTimeout을&amp;nbsp;더&amp;nbsp;길게(30초~수&amp;nbsp;분)&amp;nbsp;잡기도&amp;nbsp;합니다. &lt;br /&gt;&lt;br /&gt;외부&amp;nbsp;API&amp;nbsp;호출:&amp;nbsp;API&amp;nbsp;제공자의&amp;nbsp;SLA나&amp;nbsp;응답&amp;nbsp;속도를&amp;nbsp;참고해&amp;nbsp;5~10초&amp;nbsp;사이로&amp;nbsp;설정하는&amp;nbsp;것이&amp;nbsp;좋습니다. &lt;br /&gt;&lt;br /&gt;사용자&amp;nbsp;경험(UX):&amp;nbsp;대부분의&amp;nbsp;사용자는&amp;nbsp;10초&amp;nbsp;이상&amp;nbsp;기다리면&amp;nbsp;이탈하는&amp;nbsp;경향이&amp;nbsp;있습니다.&amp;nbsp;실제로&amp;nbsp;10~15초가&amp;nbsp;넘어가면&amp;nbsp;앱이나&amp;nbsp;웹을&amp;nbsp;종료하는&amp;nbsp;비율이&amp;nbsp;높아집니다. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;4.&amp;nbsp;오해와&amp;nbsp;바로잡기&lt;/b&gt; &lt;br /&gt;0(무한대기)로&amp;nbsp;설정해도&amp;nbsp;괜찮다? &lt;br /&gt;절대&amp;nbsp;그렇지&amp;nbsp;않습니다.&amp;nbsp;네트워크&amp;nbsp;장애나&amp;nbsp;서버&amp;nbsp;다운&amp;nbsp;시,&amp;nbsp;무한&amp;nbsp;대기&amp;nbsp;상태에&amp;nbsp;빠져&amp;nbsp;애플리케이션&amp;nbsp;전체가&amp;nbsp;멈출&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;반드시&amp;nbsp;적절한&amp;nbsp;타임아웃을&amp;nbsp;설정하세요. &lt;br /&gt;&lt;br /&gt;타임아웃이&amp;nbsp;짧을수록&amp;nbsp;무조건&amp;nbsp;좋다? &lt;br /&gt;너무&amp;nbsp;짧으면&amp;nbsp;네트워크&amp;nbsp;일시적&amp;nbsp;지연이나&amp;nbsp;서버의&amp;nbsp;순간&amp;nbsp;부하에도&amp;nbsp;실패가&amp;nbsp;빈번해집니다.&amp;nbsp;적절한&amp;nbsp;균형이&amp;nbsp;필요합니다. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;5.&amp;nbsp;구체적인&amp;nbsp;사례&lt;/b&gt; &lt;br /&gt;실제&amp;nbsp;프로젝트에서&amp;nbsp;외부&amp;nbsp;결제&amp;nbsp;API를&amp;nbsp;연동할&amp;nbsp;때,&amp;nbsp;결제사&amp;nbsp;측&amp;nbsp;SLA가&amp;nbsp;&quot;평균&amp;nbsp;2초,&amp;nbsp;최대&amp;nbsp;5초&quot;였습니다.&amp;nbsp;이때&amp;nbsp;setConnectTimeout과&amp;nbsp;setReadTimeout을&amp;nbsp;각각&amp;nbsp;5000ms로&amp;nbsp;설정했더니,&amp;nbsp;네트워크&amp;nbsp;이슈가&amp;nbsp;발생해도&amp;nbsp;5초&amp;nbsp;이내에&amp;nbsp;빠르게&amp;nbsp;장애를&amp;nbsp;감지할&amp;nbsp;수&amp;nbsp;있었습니다.&amp;nbsp;반대로,&amp;nbsp;한&amp;nbsp;번은&amp;nbsp;값을&amp;nbsp;0(무한대기)로&amp;nbsp;두었다가,&amp;nbsp;결제&amp;nbsp;서버가&amp;nbsp;다운된&amp;nbsp;상황에서&amp;nbsp;사용자들이&amp;nbsp;계속&amp;nbsp;결제&amp;nbsp;버튼만&amp;nbsp;누르고&amp;nbsp;아무&amp;nbsp;반응이&amp;nbsp;없어&amp;nbsp;큰&amp;nbsp;불편을&amp;nbsp;겪었던&amp;nbsp;적이&amp;nbsp;있습니다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론&lt;/b&gt; &lt;br /&gt;Java에서&amp;nbsp;setConnectTimeout과&amp;nbsp;setReadTimeout의&amp;nbsp;&quot;적정값&quot;은&amp;nbsp;서비스&amp;nbsp;특성,&amp;nbsp;네트워크&amp;nbsp;환경,&amp;nbsp;사용자&amp;nbsp;경험을&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두&amp;nbsp;고려해야&amp;nbsp;합니다. &lt;br /&gt;일반적으로는&amp;nbsp;5초(5000ms)가&amp;nbsp;가장&amp;nbsp;많이&amp;nbsp;쓰이는&amp;nbsp;표준값이며,&amp;nbsp;외부&amp;nbsp;환경이나&amp;nbsp;서비스&amp;nbsp;특성에&amp;nbsp;따라&amp;nbsp;10~15초까지&amp;nbsp;확장할&amp;nbsp;수&amp;nbsp;있습니다. &lt;br /&gt;무한대기(0)는&amp;nbsp;절대&amp;nbsp;피해야&amp;nbsp;하며,&amp;nbsp;실제&amp;nbsp;서비스에서는&amp;nbsp;장애&amp;nbsp;감지와&amp;nbsp;사용자&amp;nbsp;경험을&amp;nbsp;모두&amp;nbsp;고려해&amp;nbsp;적절한&amp;nbsp;값을&amp;nbsp;설정하세요.&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>HTTP</category>
      <category>https</category>
      <category>java setconnecttimeout</category>
      <category>java setreadtimeout</category>
      <category>REST API</category>
      <category>setconnecttimeout</category>
      <category>setreadtimeout</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/27</guid>
      <comments>https://neorc.tistory.com/27#entry27comment</comments>
      <pubDate>Fri, 25 Apr 2025 17:03:53 +0900</pubDate>
    </item>
    <item>
      <title>[MS-SQL] select 문에서 exist 사용하는 방법</title>
      <link>https://neorc.tistory.com/17</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;MS-SQL에서 EXISTS 문은 서브쿼리를 통해 데이터 존재 여부를 확인하는 데 사용됩니다. 이 문법은 특정 조건에 맞는 데이터가 존재하는 경우 TRUE를 반환하며, 그렇지 않으면 FALSE를 반환합니다. 아래에서 EXISTS 문법과 활용 방법을 자세히 설명합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;EXISTS&amp;nbsp;문법&lt;/b&gt; &lt;br /&gt;EXISTS는 다음과 같은 형태로 사용됩니다&lt;/p&gt;
&lt;pre id=&quot;code_1743754519741&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 컬럼명
FROM 메인테이블
WHERE EXISTS (
    SELECT 1
    FROM 서브테이블
    WHERE 조건
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;서브쿼리:&amp;nbsp;메인&amp;nbsp;쿼리와&amp;nbsp;연결된&amp;nbsp;하위&amp;nbsp;쿼리입니다.&amp;nbsp;이&amp;nbsp;하위&amp;nbsp;쿼리는&amp;nbsp;조건에&amp;nbsp;맞는&amp;nbsp;데이터가&amp;nbsp;하나라도&amp;nbsp;존재하면&amp;nbsp;TRUE를&amp;nbsp;반환합니다. &lt;br /&gt;&lt;br /&gt;SELECT&amp;nbsp;1:&amp;nbsp;서브쿼리에서&amp;nbsp;반환되는&amp;nbsp;값은&amp;nbsp;중요하지&amp;nbsp;않습니다.&amp;nbsp;따라서&amp;nbsp;일반적으로&amp;nbsp;SELECT&amp;nbsp;1&amp;nbsp;또는&amp;nbsp;SELECT&amp;nbsp;*를&amp;nbsp;사용합니다. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;EXISTS 사용 예제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;다음은 두 테이블 간의 관계를 EXISTS로 확인하는 예제입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1743754565756&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT c.custid, c.custname, c.country
FROM CUST_TABLE c
WHERE EXISTS (
    SELECT 1
    FROM ORDER_TABLE o
    WHERE o.custid = c.custid
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;이&amp;nbsp;쿼리는&amp;nbsp;CUST_TABLE에서&amp;nbsp;ORDER_TABLE에&amp;nbsp;존재하는&amp;nbsp;고객&amp;nbsp;ID만&amp;nbsp;조회합니다. &lt;br /&gt;&lt;br /&gt;결과적으로&amp;nbsp;ORDER_TABLE에&amp;nbsp;없는&amp;nbsp;고객&amp;nbsp;ID는&amp;nbsp;제외됩니다. &lt;br /&gt;&lt;br /&gt;NOT&amp;nbsp;EXISTS &lt;br /&gt;EXISTS와&amp;nbsp;반대로,&amp;nbsp;NOT&amp;nbsp;EXISTS는&amp;nbsp;서브쿼리에&amp;nbsp;데이터가&amp;nbsp;존재하지&amp;nbsp;않을&amp;nbsp;경우&amp;nbsp;TRUE를&amp;nbsp;반환합니다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1743754581759&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT c.custid, c.custname, c.country
FROM CUST_TABLE c
WHERE NOT EXISTS (
    SELECT 1
    FROM ORDER_TABLE o
    WHERE o.custid = c.custid
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이&amp;nbsp;쿼리는&amp;nbsp;ORDER_TABLE에&amp;nbsp;없는&amp;nbsp;고객&amp;nbsp;ID만&amp;nbsp;조회합니다. &lt;br /&gt;&lt;br /&gt;CASE&amp;nbsp;표현식에서&amp;nbsp;EXISTS&amp;nbsp;활용 &lt;br /&gt;EXISTS는&amp;nbsp;조건문으로도&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;아래는&amp;nbsp;CASE&amp;nbsp;WHEN과&amp;nbsp;함께&amp;nbsp;사용하는&amp;nbsp;예제입니다: &lt;/p&gt;
&lt;pre id=&quot;code_1743754598097&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT a.deptno, a.dname,
       CASE WHEN EXISTS (
           SELECT 1
           FROM emp b
           WHERE b.sal BETWEEN 500 AND 1300 AND b.deptno = a.deptno
       )
       THEN 'Y'
       ELSE 'N'
       END AS exists_yn
FROM dept a&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이&amp;nbsp;쿼리는&amp;nbsp;특정&amp;nbsp;부서에&amp;nbsp;속한&amp;nbsp;직원의&amp;nbsp;급여가&amp;nbsp;조건을&amp;nbsp;만족하면&amp;nbsp;'Y',&amp;nbsp;그렇지&amp;nbsp;않으면&amp;nbsp;'N'을&amp;nbsp;반환합니다. &lt;br /&gt;&lt;br /&gt;EXISTS&amp;nbsp;vs&amp;nbsp;IN&amp;nbsp;연산자 &lt;br /&gt;EXISTS와&amp;nbsp;IN은&amp;nbsp;유사한&amp;nbsp;기능을&amp;nbsp;제공하지만,&amp;nbsp;성능&amp;nbsp;측면에서&amp;nbsp;차이가&amp;nbsp;있습니다: &lt;br /&gt;&lt;br /&gt;특징 EXISTS IN &lt;br /&gt;서브쿼리&amp;nbsp;검색&amp;nbsp;방식 조건을&amp;nbsp;만족하는&amp;nbsp;첫&amp;nbsp;번째&amp;nbsp;행을&amp;nbsp;찾으면&amp;nbsp;종료 모든&amp;nbsp;행을&amp;nbsp;검색하여&amp;nbsp;값을&amp;nbsp;비교 &lt;br /&gt;성능 서브쿼리가&amp;nbsp;클&amp;nbsp;경우&amp;nbsp;더&amp;nbsp;효율적 작은&amp;nbsp;서브쿼리에서는&amp;nbsp;성능&amp;nbsp;차이가&amp;nbsp;없음 &lt;br /&gt;사용&amp;nbsp;가능&amp;nbsp;데이터&amp;nbsp;타입 서브쿼리만&amp;nbsp;가능 직접&amp;nbsp;값&amp;nbsp;대입&amp;nbsp;가능 &lt;br /&gt;따라서&amp;nbsp;서브쿼리의&amp;nbsp;데이터가&amp;nbsp;많을&amp;nbsp;경우에는&amp;nbsp;EXISTS를&amp;nbsp;사용하는&amp;nbsp;것이&amp;nbsp;더&amp;nbsp;효율적입니다. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;활용&amp;nbsp;사례&lt;/b&gt; &lt;br /&gt;데이터&amp;nbsp;존재&amp;nbsp;여부&amp;nbsp;확인 &lt;br /&gt;특정&amp;nbsp;테이블이&amp;nbsp;존재할&amp;nbsp;경우&amp;nbsp;실행되는&amp;nbsp;조건문: &lt;/p&gt;
&lt;pre id=&quot;code_1743754612110&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '테이블명')
BEGIN
    PRINT '테이블이 존재합니다.'
END&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;데이터&amp;nbsp;삽입&amp;nbsp;및&amp;nbsp;업데이트 &lt;br /&gt;INSERT나&amp;nbsp;UPDATE&amp;nbsp;구문에서도&amp;nbsp;EXISTS를&amp;nbsp;활용할&amp;nbsp;수&amp;nbsp;있습니다: &lt;/p&gt;
&lt;pre id=&quot;code_1743754634282&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE 테이블명
SET 컬럼명 = 값
WHERE EXISTS (
    SELECT 1 
    FROM 다른테이블 
    WHERE 조건
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;결론&lt;/b&gt; &lt;br /&gt;MS-SQL의&amp;nbsp;EXISTS&amp;nbsp;문은&amp;nbsp;데이터의&amp;nbsp;존재&amp;nbsp;여부를&amp;nbsp;효율적으로&amp;nbsp;판단할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;강력한&amp;nbsp;도구입니다.&amp;nbsp;특히&amp;nbsp;대규모&amp;nbsp;데이터&amp;nbsp;처리&amp;nbsp;시&amp;nbsp;성능상의&amp;nbsp;이점이&amp;nbsp;크며,&amp;nbsp;다양한&amp;nbsp;상황에서&amp;nbsp;활용&amp;nbsp;가능합니다.&amp;nbsp;이를&amp;nbsp;통해&amp;nbsp;복잡한&amp;nbsp;데이터&amp;nbsp;관계를&amp;nbsp;간단하고&amp;nbsp;직관적으로&amp;nbsp;처리할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;</description>
      <category>DBMS/MS-SQL</category>
      <category>EXISTS</category>
      <category>ms-sql exists</category>
      <category>mssql</category>
      <category>mssql exists</category>
      <category>select</category>
      <category>select exists</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/17</guid>
      <comments>https://neorc.tistory.com/17#entry17comment</comments>
      <pubDate>Fri, 4 Apr 2025 17:19:14 +0900</pubDate>
    </item>
    <item>
      <title>알리익스프레스 배송조회하기 송장 번호만 있으면 조회하는 방법</title>
      <link>https://neorc.tistory.com/16</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;알리익스프레스에서 송장번호를 조회하려면 다음 단계를 따라야 합니다: &lt;br /&gt;&lt;br /&gt;&lt;u&gt;&lt;b&gt;1.&amp;nbsp;알리익스프레스&amp;nbsp;공식&amp;nbsp;웹사이트에서&amp;nbsp;조회&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;알리익스프레스&amp;nbsp;계정에&amp;nbsp;로그인합니다. &lt;br /&gt;&lt;br /&gt;&quot;내&amp;nbsp;주문(My&amp;nbsp;Orders)&quot;&amp;nbsp;메뉴로&amp;nbsp;이동합니다. &lt;br /&gt;&lt;br /&gt;조회하고자&amp;nbsp;하는&amp;nbsp;주문을&amp;nbsp;선택한&amp;nbsp;후,&amp;nbsp;송장번호(Tracking&amp;nbsp;Number)를&amp;nbsp;클릭하여&amp;nbsp;배송&amp;nbsp;상태를&amp;nbsp;확인합니다. &lt;br /&gt;&lt;br /&gt;&lt;u&gt;&lt;b&gt;2.&amp;nbsp;제3자&amp;nbsp;추적&amp;nbsp;사이트&amp;nbsp;사용&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;송장번호를&amp;nbsp;입력하여&amp;nbsp;배송&amp;nbsp;상태를&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;신뢰할&amp;nbsp;만한&amp;nbsp;사이트:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.17track.net/ko&quot;&gt;올인원 소포 추적 | 17TRACK&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;17TRACK:&amp;nbsp;송장번호를&amp;nbsp;입력하면&amp;nbsp;현재&amp;nbsp;위치와&amp;nbsp;예상&amp;nbsp;도착일을&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1542&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3QMFV/btsM6BS3SrA/dWXFMSw0jPUt0WBtVKuywk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3QMFV/btsM6BS3SrA/dWXFMSw0jPUt0WBtVKuywk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3QMFV/btsM6BS3SrA/dWXFMSw0jPUt0WBtVKuywk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3QMFV%2FbtsM6BS3SrA%2FdWXFMSw0jPUt0WBtVKuywk%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;1542&quot; height=&quot;766&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1542&quot; data-origin-height=&quot;766&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;ParcelsApp:&amp;nbsp;여러&amp;nbsp;운송&amp;nbsp;회사의&amp;nbsp;정보를&amp;nbsp;통합하여&amp;nbsp;실시간&amp;nbsp;배송&amp;nbsp;상태를&amp;nbsp;제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알리익스프레스 배송추적은 최적같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://parcelsapp.com/&quot;&gt;Universal Parcel Tracking - Global Package Tracking&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1537&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ebB7WG/btsM7ggA772/usCPYCfvioQcpcdiIlXcy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ebB7WG/btsM7ggA772/usCPYCfvioQcpcdiIlXcy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ebB7WG/btsM7ggA772/usCPYCfvioQcpcdiIlXcy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FebB7WG%2FbtsM7ggA772%2FusCPYCfvioQcpcdiIlXcy0%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;1537&quot; height=&quot;670&quot; data-origin-width=&quot;1537&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;847&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8O9ZB/btsM5AHBvhr/mkwvu7hmHKK9dmVPMXIWs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8O9ZB/btsM5AHBvhr/mkwvu7hmHKK9dmVPMXIWs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8O9ZB/btsM5AHBvhr/mkwvu7hmHKK9dmVPMXIWs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8O9ZB%2FbtsM5AHBvhr%2Fmkwvu7hmHKK9dmVPMXIWs1%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;1149&quot; height=&quot;847&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;847&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Ship24:&amp;nbsp;알리익스프레스와&amp;nbsp;연계된&amp;nbsp;배송&amp;nbsp;추적&amp;nbsp;정보를&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.ship24.com/ko&quot;&gt;PARCEL TRACKING-패키지 및 배송 배송 추적 | 배송 24&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1443&quot; data-origin-height=&quot;701&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IXPDO/btsM6VDNIuA/5FnWPRW8YxAw9zlKKcs56K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IXPDO/btsM6VDNIuA/5FnWPRW8YxAw9zlKKcs56K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IXPDO/btsM6VDNIuA/5FnWPRW8YxAw9zlKKcs56K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIXPDO%2FbtsM6VDNIuA%2F5FnWPRW8YxAw9zlKKcs56K%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;1443&quot; height=&quot;701&quot; data-origin-width=&quot;1443&quot; data-origin-height=&quot;701&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;u&gt;&lt;b&gt;3.&amp;nbsp;한국&amp;nbsp;내&amp;nbsp;배송&amp;nbsp;조회&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;한국&amp;nbsp;세관을&amp;nbsp;통과한&amp;nbsp;후에는&amp;nbsp;CJ대한통운,&amp;nbsp;한진택배,&amp;nbsp;롯데택배&amp;nbsp;등&amp;nbsp;국내&amp;nbsp;택배사에서&amp;nbsp;실시간으로&amp;nbsp;배송&amp;nbsp;상태를&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;송장번호가&amp;nbsp;59~로&amp;nbsp;시작하는&amp;nbsp;경우&amp;nbsp;CJ대한통운일&amp;nbsp;가능성이&amp;nbsp;높습니다. &lt;br /&gt;&lt;br /&gt;참고&amp;nbsp;사항 &lt;br /&gt;송장번호는&amp;nbsp;주문&amp;nbsp;후&amp;nbsp;몇&amp;nbsp;일이&amp;nbsp;지나야&amp;nbsp;활성화될&amp;nbsp;수&amp;nbsp;있으므로,&amp;nbsp;처음에는&amp;nbsp;조회되지&amp;nbsp;않을&amp;nbsp;수도&amp;nbsp;있습니다.&amp;nbsp;이&amp;nbsp;경우&amp;nbsp;1~3일&amp;nbsp;정도&amp;nbsp;기다린&amp;nbsp;후&amp;nbsp;다시&amp;nbsp;시도하세요. &lt;br /&gt;&lt;br /&gt;세관&amp;nbsp;통과&amp;nbsp;전에는&amp;nbsp;중국&amp;nbsp;내&amp;nbsp;배송&amp;nbsp;추적만&amp;nbsp;가능하며,&amp;nbsp;이후&amp;nbsp;한국&amp;nbsp;택배사에서&amp;nbsp;조회&amp;nbsp;가능합니다. &lt;br /&gt;&lt;br /&gt;위&amp;nbsp;방법을&amp;nbsp;따라&amp;nbsp;송장번호를&amp;nbsp;입력하면&amp;nbsp;정확한&amp;nbsp;배송&amp;nbsp;상태를&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;</description>
      <category>기타</category>
      <category>배송조회</category>
      <category>송장번호 조회</category>
      <category>송장조회</category>
      <category>알리 배송조회</category>
      <category>알리 송장번호</category>
      <category>알리익스프레스 배송조회</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/16</guid>
      <comments>https://neorc.tistory.com/16#entry16comment</comments>
      <pubDate>Thu, 3 Apr 2025 14:15:29 +0900</pubDate>
    </item>
    <item>
      <title>HttpsURLConnection 사용 시 발생한 JSON parse error: invalid UTF-8 middle byte 0x3f 오류</title>
      <link>https://neorc.tistory.com/15</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;HttpsURLConnection 사용 시 발생한 JSON parse error: invalid UTF-8 middle byte 0x??&lt;br /&gt;오류는 일반적으로 잘못된 인코딩 문제로 인해 발생합니다.&lt;/blockquote&gt;
&lt;p data-end=&quot;132&quot; data-start=&quot;120&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;120&quot; data-end=&quot;132&quot; data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하려면:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot; data-start=&quot;133&quot; data-end=&quot;264&quot;&gt;
&lt;li data-start=&quot;133&quot; data-end=&quot;172&quot;&gt;&lt;b&gt;JSON 데이터를 UTF-8로 정확히 변환&lt;/b&gt;해야 합니다.&lt;/li&gt;
&lt;li data-start=&quot;173&quot; data-end=&quot;228&quot;&gt;&lt;b&gt;OutputStreamWriter를 사용하여 명확한 인코딩 설정&lt;/b&gt;을 해야 합니다.&lt;/li&gt;
&lt;li data-start=&quot;229&quot; data-end=&quot;264&quot;&gt;&lt;b&gt;서버가 기대하는 인코딩 형식을 확인&lt;/b&gt;해야 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-end=&quot;282&quot; data-start=&quot;266&quot; data-ke-size=&quot;size23&quot;&gt;  &lt;b&gt;해결 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;322&quot; data-start=&quot;283&quot; data-ke-size=&quot;size16&quot;&gt;코드를 아래와 같이 수정하면 UTF-8 문제를 방지할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1742282338576&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;

public class RestApiClient {
    public static String sendHttpRequest(String targetUrl, String method, String jsonBody) {
        StringBuilder response = new StringBuilder();
        HttpURLConnection conn = null;
        OutputStream os = null;
        BufferedReader br = null;
        
        try {
            URL url = new URL(targetUrl);
            
            if (targetUrl.startsWith(&quot;https&quot;)) {
                conn = (HttpsURLConnection) url.openConnection();
            } else {
                conn = (HttpURLConnection) url.openConnection();
            }
            
            conn.setRequestMethod(method);
            conn.setRequestProperty(&quot;Content-Type&quot;, &quot;application/json; charset=UTF-8&quot;);
            conn.setRequestProperty(&quot;Accept-Charset&quot;, &quot;UTF-8&quot;);
            conn.setDoOutput(true);
            
            if (jsonBody != null &amp;amp;&amp;amp; jsonBody.length() &amp;gt; 0) {
                os = conn.getOutputStream();
                os.write(jsonBody.getBytes(&quot;UTF-8&quot;));
                os.flush();
            }
            
            int responseCode = conn.getResponseCode();
            System.out.println(&quot;HTTP Response Code: &quot; + responseCode);
            
            InputStream inputStream;
            if (responseCode &amp;gt;= 200 &amp;amp;&amp;amp; responseCode &amp;lt; 300) {
                inputStream = conn.getInputStream();
            } else {
                inputStream = conn.getErrorStream();
            }
            
            if (inputStream != null) {
                br = new BufferedReader(new InputStreamReader(inputStream, &quot;UTF-8&quot;));
                String responseLine;
                while ((responseLine = br.readLine()) != null) {
                    response.append(responseLine.trim());
                }
            }
        } catch (IOException e) {
            System.err.println(&quot;HTTP 요청 중 오류 발생: &quot; + e.getMessage());
        } finally {
            try {
                if (os != null) os.close();
                if (br != null) br.close();
                if (conn != null) conn.disconnect();
            } catch (IOException e) {
                System.err.println(&quot;리소스 해제 중 오류 발생: &quot; + e.getMessage());
            }
        }
        return response.toString();
    }

    public static void main(String[] args) {
        String url = &quot;https://example.com/api&quot;;
        String method = &quot;POST&quot;;
        String jsonBody = &quot;{\&quot;message\&quot;:\&quot;Hello, API!\&quot;}&quot;;

        String response = sendHttpRequest(url, method, jsonBody);
        System.out.println(&quot;Response: &quot; + response);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-end=&quot;2736&quot; data-start=&quot;2717&quot; data-ke-size=&quot;size23&quot;&gt;  &lt;b&gt;핵심 개선 사항&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2935&quot; data-start=&quot;2737&quot; data-ke-size=&quot;size16&quot;&gt;✅ OutputStreamWriter를 사용하여 &lt;b&gt;UTF-8로 인코딩&lt;/b&gt;&lt;br /&gt;✅ &quot;Content-Type: application/json; charset=UTF-8&quot; 헤더 추가&lt;br /&gt;✅ &quot;Accept-Charset: UTF-8&quot; 헤더 추가&lt;br /&gt;✅ OutputStreamWriter.flush() 호출하여 &lt;b&gt;출력 스트림을 강제 비우기&lt;/b&gt;&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>accept-charset</category>
      <category>header</category>
      <category>httpsurlconnection</category>
      <category>java</category>
      <category>JSON</category>
      <category>json parse</category>
      <category>OutputStreamWriter</category>
      <category>urf-8 인코딩</category>
      <category>인코딩 오류</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/15</guid>
      <comments>https://neorc.tistory.com/15#entry15comment</comments>
      <pubDate>Tue, 18 Mar 2025 16:21:21 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 이미지 파일 크기 조정 및 생성하기</title>
      <link>https://neorc.tistory.com/14</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;웹사이트나 모바일 앱에서 이미지 크기 조정은 매우 중요한 작업입니다. 특히 SEO(검색 엔진 최적화)를 고려할 때, 적절한 이미지 크기와 압축은 페이지 로딩 속도를 개선하고 검색 엔진 순위를 높이는 데 도움이 됩니다. Java에서는 BufferedImage와 Graphics2D를 활용하여 이미지 크기 조정 및 파일 생성이 가능합니다.  ✨&lt;br /&gt;이 글에서는 Java를 사용하여 이미지 크기를 조정하는 방법을 자세히 설명하겠습니다!&lt;/blockquote&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;이미지 크기 조정 및 저장하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java에서는 &lt;/span&gt;&lt;span&gt;BufferedImage&lt;/span&gt;&lt;span&gt;를 활용하여 이미지 크기를 조정한 후, 파일로 저장할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class ResizeImage {
    public static void main(String[] args) {
        try {
            // 원본 이미지 불러오기
            File inputFile = new File(&quot;input.jpg&quot;);
            BufferedImage inputImage = ImageIO.read(inputFile);
            
            // 새로운 크기 지정
            int newWidth = 500;
            int newHeight = 300;
            
            // 새로운 이미지 생성
            BufferedImage outputImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = outputImage.createGraphics();
            g2d.drawImage(inputImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH), 0, 0, null);
            g2d.dispose();
            
            // 새로운 파일로 저장
            File outputFile = new File(&quot;resized_image.jpg&quot;);
            ImageIO.write(outputImage, &quot;jpg&quot;, outputFile);
            
            System.out.println(&quot;이미지 크기 조정 완료: &quot; + outputFile.getAbsolutePath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;ImageIO.read()&lt;/span&gt;&lt;span&gt; &amp;rarr; 기존 이미지 파일을 읽어옵니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;BufferedImage&lt;/span&gt;&lt;span&gt; &amp;rarr; 새 이미지 크기를 지정하여 생성합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;Graphics2D&lt;/span&gt;&lt;span&gt; &amp;rarr; 원본 이미지를 &lt;/span&gt;&lt;span&gt;&lt;b&gt;부드럽게(SMOOTH)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 크기 조정하여 저장합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;ImageIO.write()&lt;/span&gt;&lt;span&gt; &amp;rarr; 변환된 이미지를 파일로 저장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;비율 유지하며 크기 조정하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이미지의 &lt;/span&gt;&lt;span&gt;&lt;b&gt;가로세로 비율을 유지하면서 크기를 조정&lt;/b&gt;&lt;/span&gt;&lt;span&gt;하려면, 비율을 계산하여 적용해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class ResizeImageWithAspectRatio {
    public static void main(String[] args) {
        try {
            File inputFile = new File(&quot;input.jpg&quot;);
            BufferedImage inputImage = ImageIO.read(inputFile);
            
            int originalWidth = inputImage.getWidth();
            int originalHeight = inputImage.getHeight();
            int targetWidth = 600;
            int targetHeight = (originalHeight * targetWidth) / originalWidth;
            
            BufferedImage outputImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = outputImage.createGraphics();
            g2d.drawImage(inputImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_SMOOTH), 0, 0, null);
            g2d.dispose();
            
            File outputFile = new File(&quot;resized_image_aspect_ratio.jpg&quot;);
            ImageIO.write(outputImage, &quot;jpg&quot;, outputFile);
            
            System.out.println(&quot;비율 유지 크기 조정 완료: &quot; + outputFile.getAbsolutePath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 원본 이미지의 &lt;/span&gt;&lt;span&gt;&lt;b&gt;가로 대비 세로 비율&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 계산하여 자동 조정합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;targetHeight = (originalHeight * targetWidth) / originalWidth;&lt;/span&gt;&lt;span&gt; &amp;rarr; 비율 유지 계산식입니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;PNG, JPG, GIF 등 다양한 포맷 변환하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java에서는 &lt;/span&gt;&lt;span&gt;ImageIO.write()&lt;/span&gt;&lt;span&gt;를 사용하여 PNG, JPG, GIF 등 다양한 이미지 포맷으로 저장할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;File outputFile = new File(&quot;output.png&quot;);
ImageIO.write(outputImage, &quot;png&quot;, outputFile);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 확장자만 변경하면 PNG, JPG, GIF 포맷으로 손쉽게 변환할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;br /&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;이미지 압축하여 파일 크기 줄이기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이미지의 품질을 유지하면서 파일 크기를 줄이려면 &lt;/span&gt;&lt;span&gt;&lt;b&gt;JPEG 압축률&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 조절하는 것이 중요합니다. 아래는 Java에서 &lt;/span&gt;&lt;span&gt;ImageWriteParam&lt;/span&gt;&lt;span&gt;을 활용한 이미지 압축 코드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.util.Iterator;

public class CompressImage {
    public static void main(String[] args) {
        try {
            File inputFile = new File(&quot;input.jpg&quot;);
            BufferedImage image = ImageIO.read(inputFile);
            
            File compressedFile = new File(&quot;compressed_image.jpg&quot;);
            FileOutputStream fos = new FileOutputStream(compressedFile);
            
            Iterator&amp;lt;ImageWriter&amp;gt; writers = ImageIO.getImageWritersByFormatName(&quot;jpg&quot;);
            ImageWriter writer = writers.next();
            ImageOutputStream ios = ImageIO.createImageOutputStream(fos);
            writer.setOutput(ios);
            
            ImageWriteParam param = writer.getDefaultWriteParam();
            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            param.setCompressionQuality(0.7f); // 0.0(최대압축) ~ 1.0(최고품질)
            
            writer.write(null, new javax.imageio.IIOImage(image, null, null), param);
            
            ios.close();
            fos.close();
            writer.dispose();
            
            System.out.println(&quot;이미지 압축 완료: &quot; + compressedFile.getAbsolutePath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;setCompressionQuality(0.7f);&lt;/span&gt;&lt;span&gt; &amp;rarr; 70% 품질 유지하며 파일 크기 감소&lt;/span&gt;&lt;br /&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;ImageWriteParam&lt;/span&gt;&lt;span&gt;을 활용하여 &lt;/span&gt;&lt;span&gt;&lt;b&gt;JPEG 압축률 조정&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;✔ 원본 품질을 유지하면서도 &lt;/span&gt;&lt;span&gt;&lt;b&gt;파일 크기를 줄일 수 있음&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;이미지 최적화&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1️⃣ &lt;/span&gt;&lt;span&gt;&lt;b&gt;파일 크기 압축하기&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &amp;rarr; WebP 또는 JPEG 압축률을 조절하여 용량을 줄일 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2️⃣ &lt;/span&gt;&lt;span&gt;&lt;b&gt;올바른 파일명 사용&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &amp;rarr; &lt;/span&gt;&lt;span&gt;java-resize-image.jpg&lt;/span&gt;&lt;span&gt;처럼 &lt;/span&gt;&lt;span&gt;&lt;b&gt;SEO-friendly 파일명&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 사용하세요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3️⃣ &lt;/span&gt;&lt;span&gt;&lt;b&gt;ALT 태그 추가하기&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &amp;rarr; 웹에서 사용 시 &lt;/span&gt;&lt;span&gt;&amp;lt;img alt=&quot;Java 이미지 크기 조정 예제&quot;&amp;gt;&lt;/span&gt;&lt;span&gt;를 추가하세요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;4️⃣ &lt;/span&gt;&lt;span&gt;&lt;b&gt;CDN 활용&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &amp;rarr; 이미지 로딩 속도를 높이기 위해 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Cloudflare, AWS S3&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 등을 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;결론 (Conclusion)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java에서 &lt;/span&gt;&lt;span&gt;&lt;b&gt;이미지 크기 조정 및 생성&lt;/b&gt;&lt;/span&gt;&lt;span&gt;하는 방법을 정리하면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;BufferedImage&lt;/span&gt;&lt;span&gt;를 사용하여 이미지 크기를 조정합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;Graphics2D&lt;/span&gt;&lt;span&gt;를 이용해 &lt;/span&gt;&lt;span&gt;&lt;b&gt;고품질로 리사이징&lt;/b&gt;&lt;/span&gt;&lt;span&gt;합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 비율을 유지한 크기 조정도 가능합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 다양한 포맷(PNG, JPG, GIF)으로 변환하여 저장할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 최적화를 위해 파일명, ALT 태그, 압축 등을 고려합니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>BufferedImage</category>
      <category>Graphics2D</category>
      <category>imageresize</category>
      <category>java 압축</category>
      <category>java 이미지처리</category>
      <category>이미지 압축</category>
      <category>자바 이미지</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/14</guid>
      <comments>https://neorc.tistory.com/14#entry14comment</comments>
      <pubDate>Fri, 14 Mar 2025 16:15:22 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 국가별 TimeZone(시간대) 처리 방법</title>
      <link>https://neorc.tistory.com/13</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;세계 각국의 시간대(TimeZone)를 고려하는 것은 국제적인 서비스 개발에서 필수적인 요소입니다. Java에서는 TimeZone과 ZonedDateTime을 활용하여 국가별 시간대를 정확하게 처리할 수 있습니다.  &lt;br /&gt;이 글에서는 Java에서 국가별 시간대(TimeZone) 처리 방법을 코드 예제와 함께 설명하겠습니다&lt;/blockquote&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;시스템 기본 TimeZone 가져오기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java에서는 &lt;/span&gt;&lt;span&gt;TimeZone.getDefault()&lt;/span&gt;&lt;span&gt;를 사용하여 현재 시스템의 기본 시간대를 가져올 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.TimeZone;

public class DefaultTimeZoneExample {
    public static void main(String[] args) {
        TimeZone defaultZone = TimeZone.getDefault();
        System.out.println(&quot;현재 시스템의 기본 시간대: &quot; + defaultZone.getID());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 실행하면 시스템 설정에 따라 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Asia/Seoul, America/New_York&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 등과 같은 값이 출력됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;특정 국가의 TimeZone 가져오기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java에서는 특정한 &lt;/span&gt;&lt;span&gt;&lt;b&gt;국가 또는 지역의 시간대&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 가져올 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.TimeZone;

public class SpecificTimeZoneExample {
    public static void main(String[] args) {
        TimeZone timeZone = TimeZone.getTimeZone(&quot;America/New_York&quot;);
        System.out.println(&quot;뉴욕의 시간대: &quot; + timeZone.getID());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;TimeZone.getTimeZone(&quot;America/New_York&quot;)&lt;/span&gt;&lt;span&gt; &amp;rarr; 뉴욕의 시간대를 가져옵니다. ✔ 다른 나라의 시간대를 가져오려면 &lt;/span&gt;&lt;span&gt;&lt;b&gt;IANA TimeZone ID&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 사용하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;모든 TimeZone ID 출력하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java에서 지원하는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;모든 시간대(TimeZone) ID 목록&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 확인할 수도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.TimeZone;

public class AllTimeZones {
    public static void main(String[] args) {
        String[] availableIDs = TimeZone.getAvailableIDs();
        for (String id : availableIDs) {
            System.out.println(id);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 실행하면 전 세계의 &lt;/span&gt;&lt;span&gt;&lt;b&gt;모든 시간대 목록&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이 출력됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;ZonedDateTime을 이용한 국가별 시간 변환&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java 8 이상에서는 &lt;/span&gt;&lt;span&gt;ZonedDateTime&lt;/span&gt;&lt;span&gt;과 &lt;/span&gt;&lt;span&gt;ZoneId&lt;/span&gt;&lt;span&gt;를 활용하여 국가별 시간 변환이 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;import java.time.ZonedDateTime;
import java.time.ZoneId;

public class ZonedDateTimeExample {
    public static void main(String[] args) {
        ZonedDateTime nowInKorea = ZonedDateTime.now(ZoneId.of(&quot;Asia/Seoul&quot;));
        ZonedDateTime nowInLondon = nowInKorea.withZoneSameInstant(ZoneId.of(&quot;Europe/London&quot;));

        System.out.println(&quot;서울 시간: &quot; + nowInKorea);
        System.out.println(&quot;런던 시간: &quot; + nowInLondon);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;ZonedDateTime.now(ZoneId.of(&quot;Asia/Seoul&quot;))&lt;/span&gt;&lt;span&gt; &amp;rarr; 현재 서울의 시간을 가져옵니다. ✔ &lt;/span&gt;&lt;span&gt;withZoneSameInstant(ZoneId.of(&quot;Europe/London&quot;))&lt;/span&gt;&lt;span&gt; &amp;rarr; 같은 순간의 런던 시간을 변환합니다. ✔ &lt;/span&gt;&lt;span&gt;ZonedDateTime&lt;/span&gt;&lt;span&gt;을 사용하면 &lt;/span&gt;&lt;span&gt;&lt;b&gt;서머타임(DST)도 자동으로 처리&lt;/b&gt;&lt;/span&gt;&lt;span&gt;됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;UTC(협정 세계시) 변환하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버에서는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;UTC 기준 시간&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 유지하는 것이 일반적입니다. Java에서는 UTC로 변환할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.time.ZonedDateTime;
import java.time.ZoneId;

public class UTCExample {
    public static void main(String[] args) {
        ZonedDateTime nowUTC = ZonedDateTime.now(ZoneId.of(&quot;UTC&quot;));
        System.out.println(&quot;현재 UTC 시간: &quot; + nowUTC);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ UTC(세계 표준시)로 변환하면 &lt;/span&gt;&lt;span&gt;&lt;b&gt;시간대에 관계없이 일정한 시간값&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 유지할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;결론 (Conclusion)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java에서 &lt;/span&gt;&lt;span&gt;&lt;b&gt;국가별 시간(TimeZone) 처리 방법&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 정리하면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;TimeZone.getDefault()&lt;/span&gt;&lt;span&gt; &amp;rarr; 시스템 기본 시간대 가져오기 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;TimeZone.getTimeZone(&quot;ID&quot;)&lt;/span&gt;&lt;span&gt; &amp;rarr; 특정 국가의 시간대 설정 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;TimeZone.getAvailableIDs()&lt;/span&gt;&lt;span&gt; &amp;rarr; 모든 시간대 목록 확인 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;ZonedDateTime.now(ZoneId.of(&quot;ID&quot;))&lt;/span&gt;&lt;span&gt; &amp;rarr; Java 8 이상에서 국가별 시간 가져오기 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;withZoneSameInstant(ZoneId.of(&quot;ID&quot;))&lt;/span&gt;&lt;span&gt; &amp;rarr; 다른 시간대로 변환하기 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;ZoneId.of(&quot;UTC&quot;)&lt;/span&gt;&lt;span&gt; &amp;rarr; UTC(세계 표준시) 변환하기&lt;/span&gt;&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>DateTime</category>
      <category>java</category>
      <category>Timezone</category>
      <category>UTC</category>
      <category>ZonedDateTime</category>
      <category>시간대처리</category>
      <category>자바 타임존</category>
      <category>타임존 처리</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/13</guid>
      <comments>https://neorc.tistory.com/13#entry13comment</comments>
      <pubDate>Fri, 14 Mar 2025 16:01:50 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 소수점 자르기(반올림, 내림, 버림) 방법</title>
      <link>https://neorc.tistory.com/12</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Java에서 소수점 이하 자리수를 조정하는 것은 다양한 프로그램에서 필수적인 기능입니다. 예를 들어, 금융 계산에서 소수점 두 자리까지 표시하거나, 특정한 자리수까지만 반올림해야 할 때가 있습니다.&lt;br /&gt;Java에서는 Math 클래스와 BigDecimal 클래스를 활용하여 소수점 처리를 쉽게 할 수 있습니다. 이 글에서는 소수점 반올림, 올림, 내림, 버림 등 다양한 방법을 코드 예제와 함께 소개하겠습니다&lt;/blockquote&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;Math.round()로 반올림하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Math.round()&lt;/span&gt;&lt;span&gt; 메서드는 가장 간단한 반올림 방법입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;소수점 첫째 자리에서 반올림하는 예제:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class RoundingExample {
    public static void main(String[] args) {
        double num = 3.567;
        long rounded = Math.round(num); // 소수점 첫째 자리에서 반올림
        System.out.println(&quot;반올림 결과: &quot; + rounded); // 출력: 4
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;Math.round(3.567)&lt;/span&gt;&lt;span&gt; &amp;rarr; &lt;/span&gt;&lt;span&gt;&lt;b&gt;4&lt;/b&gt;&lt;/span&gt;&lt;span&gt;로 반올림됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 기본적으로 &lt;/span&gt;&lt;span&gt;&lt;b&gt;소수점 첫째 자리에서 반올림&lt;/b&gt;&lt;/span&gt;&lt;span&gt;하는 특징이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;Math.ceil()로 올림하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Math.ceil()&lt;/span&gt;&lt;span&gt;은 항상 &lt;/span&gt;&lt;span&gt;&lt;b&gt;올림(반올림이 아니라 무조건 큰 값으로 올림)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 처리를 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;소수점 올림 예제:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class CeilExample {
    public static void main(String[] args) {
        double num = 3.14;
        double ceilValue = Math.ceil(num);
        System.out.println(&quot;올림 결과: &quot; + ceilValue); // 출력: 4.0
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;Math.ceil(3.14)&lt;/span&gt;&lt;span&gt; &amp;rarr; &lt;/span&gt;&lt;span&gt;&lt;b&gt;4.0&lt;/b&gt;&lt;/span&gt;&lt;span&gt;으로 올림됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 무조건 &lt;/span&gt;&lt;span&gt;&lt;b&gt;큰 정수로 올림&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이 되기 때문에, 특정 자리에서 반올림을 원하는 경우에는 사용하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;Math.floor()로 내림(버림)하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Math.floor()&lt;/span&gt;&lt;span&gt;는 항상 &lt;/span&gt;&lt;span&gt;&lt;b&gt;내림(작은 값으로 버림)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;소수점 내림 예제:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class FloorExample {
    public static void main(String[] args) {
        double num = 3.98;
        double floorValue = Math.floor(num);
        System.out.println(&quot;내림 결과: &quot; + floorValue); // 출력: 3.0
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;Math.floor(3.98)&lt;/span&gt;&lt;span&gt; &amp;rarr; &lt;/span&gt;&lt;span&gt;&lt;b&gt;3.0&lt;/b&gt;&lt;/span&gt;&lt;span&gt;으로 내림됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 항상 작은 정수로 변환되기 때문에, 특정 자리에서 반올림을 원할 경우 적절하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;BigDecimal을 이용한 소수점 자리수 제한&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;금융 계산처럼 정확한 소수점 처리가 필요할 때는 &lt;/span&gt;&lt;span&gt;BigDecimal&lt;/span&gt;&lt;span&gt;을 사용하는 것이 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;소수점 둘째 자리까지 반올림하는 예제:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.math.BigDecimal;
import java.math.RoundingMode;

public class BigDecimalExample {
    public static void main(String[] args) {
        BigDecimal num = new BigDecimal(&quot;3.56789&quot;);
        BigDecimal roundedNum = num.setScale(2, RoundingMode.HALF_UP);
        System.out.println(&quot;소수점 둘째 자리 반올림: &quot; + roundedNum); // 출력: 3.57
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;setScale(2, RoundingMode.HALF_UP)&lt;/span&gt;&lt;span&gt; &amp;rarr; 소수점 둘째 자리에서 반올림됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;RoundingMode.HALF_UP&lt;/span&gt;&lt;span&gt;은 일반적인 &lt;/span&gt;&lt;span&gt;&lt;b&gt;5에서 반올림&lt;/b&gt;&lt;/span&gt;&lt;span&gt;하는 방식입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;BigDecimal&lt;/span&gt;&lt;span&gt;을 사용하면 &lt;/span&gt;&lt;span&gt;&lt;b&gt;정확한 계산이 가능&lt;/b&gt;&lt;/span&gt;&lt;span&gt;하여 금융 프로그램에서 자주 활용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;다양한 RoundingMode 옵션:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;RoundingMode.UP&lt;/span&gt;&lt;span&gt; &amp;rarr; 무조건 올림&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;RoundingMode.DOWN&lt;/span&gt;&lt;span&gt; &amp;rarr; 무조건 버림&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;RoundingMode.HALF_UP&lt;/span&gt;&lt;span&gt; &amp;rarr; 일반적인 반올림(5 이상 올림)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;RoundingMode.HALF_DOWN&lt;/span&gt;&lt;span&gt; &amp;rarr; 5일 경우 버림&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;RoundingMode.HALF_EVEN&lt;/span&gt;&lt;span&gt; &amp;rarr; 은행가 반올림 방식&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;특정 자리수에서 반올림하는 사용자 정의 함수&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자주 사용되는 소수점 처리를 위한 &lt;/span&gt;&lt;span&gt;&lt;b&gt;유틸리티 메서드&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 만들어 활용할 수도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;소수점 n번째 자리에서 반올림하는 메서드:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class RoundUtil {
    public static double round(double value, int places) {
        if (places &amp;lt; 0) throw new IllegalArgumentException(&quot;소수점 자리수는 0 이상이어야 합니다.&quot;);
        
        BigDecimal bd = new BigDecimal(Double.toString(value));
        bd = bd.setScale(places, RoundingMode.HALF_UP);
        return bd.doubleValue();
    }
    
    public static void main(String[] args) {
        System.out.println(&quot;소수점 둘째 자리 반올림: &quot; + round(3.56789, 2)); // 출력: 3.57
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;round(3.56789, 2)&lt;/span&gt;&lt;span&gt; &amp;rarr; &lt;/span&gt;&lt;span&gt;&lt;b&gt;3.57&lt;/b&gt;&lt;/span&gt;&lt;span&gt; (소수점 둘째 자리에서 반올림) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 여러 자리수에서도 사용할 수 있도록 &lt;/span&gt;&lt;span&gt;&lt;b&gt;유연한 코드&lt;/b&gt;&lt;/span&gt;&lt;span&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;결론 (Conclusion)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java에서 &lt;/span&gt;&lt;span&gt;&lt;b&gt;소수점 이하 자르기(반올림, 내림, 버림)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 방법을 정리하면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;Math.round()&lt;/span&gt;&lt;span&gt; &amp;rarr; 기본 반올림(소수 첫째 자리 기준) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;Math.ceil()&lt;/span&gt;&lt;span&gt; &amp;rarr; 무조건 올림 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;Math.floor()&lt;/span&gt;&lt;span&gt; &amp;rarr; 무조건 내림(버림) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;BigDecimal&lt;/span&gt;&lt;span&gt; &amp;rarr; 금융 계산 등 정밀한 연산을 위한 추천 방법 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;setScale(n, RoundingMode.XXX)&lt;/span&gt;&lt;span&gt; &amp;rarr; 원하는 자리수에서 반올림 가능 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 사용자 정의 함수(&lt;/span&gt;&lt;span&gt;round(value, places)&lt;/span&gt;&lt;span&gt;)로 유연한 소수점 처리가 가능&lt;/span&gt;&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>BigDecimal</category>
      <category>java</category>
      <category>math</category>
      <category>내림</category>
      <category>반올림</category>
      <category>버림</category>
      <category>소수점처리</category>
      <category>소숫점</category>
      <category>올림</category>
      <category>자바소수점</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/12</guid>
      <comments>https://neorc.tistory.com/12#entry12comment</comments>
      <pubDate>Fri, 14 Mar 2025 15:54:28 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Date 객체와 날짜 처리 방법</title>
      <link>https://neorc.tistory.com/11</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Java에서 날짜와 시간을 다루는 것은 개발에서 필수적인 요소 중 하나입니다. 예를 들어, 사용자의 가입일을 기록하거나, 특정 작업의 수행 시간을 측정할 때 날짜 처리가 필요합니다.&lt;br /&gt;하지만, Java의 날짜 처리는 여러 가지 방식이 존재하며, Date, Calendar, LocalDateTime 등 다양한 클래스가 존재합니다. 이번 글에서는 Date 객체를 중심으로 날짜 처리 방법을 살펴보고, 보다 현대적인 java.time 패키지 활용법도 간단히 소개하겠습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;Date 객체 사용하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java의 &lt;/span&gt;&lt;span&gt;java.util.Date&lt;/span&gt;&lt;span&gt; 클래스는 가장 기본적인 날짜 처리 클래스입니다. 하지만 &lt;/span&gt;&lt;span&gt;Date&lt;/span&gt;&lt;span&gt; 클래스는 내부적으로 UTC(협정 세계시)를 기반으로 하고 있으며, 시간대를 직접 설정할 수 없다는 단점이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741849637844&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Date;

public class DateExample {
    public static void main(String[] args) {
        Date now = new Date(); // 현재 날짜 및 시간
        System.out.println(&quot;현재 날짜 및 시간: &quot; + now);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;SimpleDateFormat으로 날짜 포맷 변환하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;날짜 데이터를 원하는 형식으로 변환하려면 &lt;/span&gt;&lt;span&gt;SimpleDateFormat&lt;/span&gt;&lt;span&gt;을 사용해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741849689937&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.text.SimpleDateFormat;
import java.util.Date;

public class DateFormatExample {
    public static void main(String[] args) {
        Date now = new Date();
        SimpleDateFormat formatter = new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;);
        String formattedDate = formatter.format(now);
        System.out.println(&quot;포맷된 날짜: &quot; + formattedDate);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;yyyy-MM-dd HH:mm:ss&lt;/span&gt;&lt;span&gt; 형식으로 출력되며, 원하는 형태로 변경 가능합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;&lt;b&gt;주의:&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SimpleDateFormat&lt;/span&gt;&lt;span&gt;은 &lt;/span&gt;&lt;span&gt;&lt;b&gt;스레드 안전하지 않으므로&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, 멀티스레드 환경에서는 &lt;/span&gt;&lt;span&gt;ThreadLocal&lt;/span&gt;&lt;span&gt;을 활용하거나 &lt;/span&gt;&lt;span&gt;java.time&lt;/span&gt;&lt;span&gt; 패키지를 사용하는 것이 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;Calendar 클래스로 날짜 조작하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Date&lt;/span&gt;&lt;span&gt; 클래스만으로는 날짜 연산이 어렵기 때문에, &lt;/span&gt;&lt;span&gt;Calendar&lt;/span&gt;&lt;span&gt; 클래스를 활용해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741849788244&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Calendar;
import java.util.Date;

public class CalendarExample {
    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, 5); // 5일 후 날짜 계산
        Date futureDate = calendar.getTime();
        System.out.println(&quot;5일 후 날짜: &quot; + futureDate);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;Calendar.getInstance()&lt;/span&gt;&lt;span&gt;를 사용하여 객체를 생성하고, &lt;/span&gt;&lt;span&gt;add()&lt;/span&gt;&lt;span&gt; 메서드로 날짜를 변경할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 하지만 &lt;/span&gt;&lt;span&gt;Calendar&lt;/span&gt;&lt;span&gt; 클래스 역시 직관성이 떨어지고 사용하기 불편하다는 단점이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;java.time 패키지(LocalDate, LocalDateTime) 활용하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java 8 이후부터는 &lt;/span&gt;&lt;span&gt;java.time&lt;/span&gt;&lt;span&gt; 패키지를 사용하여 날짜 및 시간을 더욱 쉽게 다룰 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741849756602&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class LocalDateExample {
    public static void main(String[] args) {
        LocalDate today = LocalDate.now(); // 현재 날짜
        System.out.println(&quot;현재 날짜: &quot; + today);

        LocalDate futureDate = today.plusDays(10); // 10일 후 계산
        System.out.println(&quot;10일 후: &quot; + futureDate);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;LocalDate.now()&lt;/span&gt;&lt;span&gt;를 사용하면 간단하게 현재 날짜를 가져올 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;plusDays()&lt;/span&gt;&lt;span&gt; 같은 메서드를 활용하여 날짜를 쉽게 연산할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;java.time&lt;/span&gt;&lt;span&gt; 패키지는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;불변 객체(immutable)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 로 설계되어 있어 스레드 안전(thread-safe)합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;날짜 문자열 변환 및 비교하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;날짜를 문자열로 변환하거나, 두 날짜를 비교하는 방법도 자주 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;문자열 &amp;rarr; 날짜 변환&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;DateTimeFormatter formatter = DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd&quot;);
LocalDate date = LocalDate.parse(&quot;2024-02-20&quot;, formatter);
System.out.println(&quot;문자열에서 변환된 날짜: &quot; + date);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;두 날짜 비교하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;LocalDate date1 = LocalDate.of(2024, 2, 10);
LocalDate date2 = LocalDate.of(2024, 2, 20);

if (date1.isBefore(date2)) {
    System.out.println(&quot;date1이 date2보다 이전 날짜입니다.&quot;);
} else {
    System.out.println(&quot;date1이 date2보다 이후 날짜입니다.&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;isBefore()&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;isAfter()&lt;/span&gt;&lt;span&gt; 메서드를 사용하여 날짜를 직관적으로 비교할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;결론 (Conclusion)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지금까지 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Java에서 날짜와 시간을 다루는 방법&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 살펴보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;Date&lt;/span&gt;&lt;span&gt; 클래스는 기본적인 날짜 표현을 제공하지만, 다소 불편한 점이 많습니다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;Calendar&lt;/span&gt;&lt;span&gt; 클래스는 날짜 조작 기능을 제공하지만, API가 직관적이지 않습니다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;✔ &lt;/span&gt;&lt;span&gt;java.time&lt;/span&gt;&lt;span&gt; 패키지(&lt;/span&gt;&lt;span&gt;LocalDate&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;LocalDateTime&lt;/span&gt;&lt;span&gt;)는 최신 Java에서 권장되는 방식으로, &lt;/span&gt;&lt;span&gt;&lt;b&gt;불변성 및 가독성이 뛰어납니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 새로운 프로젝트를 시작한다면 &lt;/span&gt;&lt;span&gt;java.time&lt;/span&gt;&lt;span&gt; 패키지를 적극 활용하는 것이 좋습니다. 기존 코드와의 호환성이 필요할 경우 &lt;/span&gt;&lt;span&gt;Date&lt;/span&gt;&lt;span&gt;와 &lt;/span&gt;&lt;span&gt;Calendar&lt;/span&gt;&lt;span&gt;도 함께 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>calendar</category>
      <category>Date</category>
      <category>DateTime</category>
      <category>java</category>
      <category>javatime</category>
      <category>LocalDate</category>
      <category>날짜처리</category>
      <category>일자처리</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/11</guid>
      <comments>https://neorc.tistory.com/11#entry11comment</comments>
      <pubDate>Thu, 13 Mar 2025 16:12:35 +0900</pubDate>
    </item>
    <item>
      <title>Windows 10, 11에서 파일 탐색기 오류 해결방법</title>
      <link>https://neorc.tistory.com/10</link>
      <description>&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;1. Window 탐색기 오류&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Windows를 사용하다 보면 &lt;/span&gt;&lt;span&gt;&lt;b&gt;파일 탐색기 오류&lt;/b&gt;&lt;/span&gt;&lt;span&gt;가 발생하는 경우가 많습니다. 파일 탐색기가 갑자기 멈추거나 응답하지 않거나, 열리지 않는 등의 문제가 생길 수 있는데요. 특히 Windows 10과 11에서는 이런 문제가 빈번하게 발생하는 경우가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 글에서는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;파일 탐색기 오류 해결방법&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 하나씩 단계적으로 살펴보겠습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;2. 탐색기 오류 해결방법&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;1) 파일 탐색기 다시 시작하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가장 간단한 해결방법은 파일 탐색기를 다시 시작하는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;방법:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Ctrl + Shift + Esc&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 키를 눌러 &lt;/span&gt;&lt;span&gt;&lt;b&gt;작업 관리자&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 엽니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&quot;프로세스&quot; 탭에서 **파일 탐색기(Windows Explorer)**를 찾습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;마우스 오른쪽 버튼을 클릭한 후, &quot;다시 시작&quot;을 선택합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 방법은 간단하지만, 탐색기 오류의 많은 문제를 해결할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;2) 파일 탐색기 설정 초기화하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;파일 탐색기 설정이 꼬이면 오류가 발생할 수 있습니다. 이때, 설정을 초기화하면 문제가 해결될 수도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;방법:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;파일 탐색기&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 엽니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;상단의 &lt;/span&gt;&lt;span&gt;&lt;b&gt;보기&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 탭에서 &lt;/span&gt;&lt;span&gt;&lt;b&gt;옵션&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 선택합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&quot;폴더 옵션&quot; 창이 뜨면 &lt;/span&gt;&lt;span&gt;&lt;b&gt;기본값 복원&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 버튼을 클릭합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 방법을 통해 탐색기의 모든 설정이 기본값으로 돌아갑니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;3) Windows 업데이트 확인하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;파일 탐색기 오류는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Windows 업데이트&lt;/b&gt;&lt;/span&gt;&lt;span&gt;가 원인일 수도 있습니다. 최신 업데이트를 설치하면 오류가 해결될 가능성이 높습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;방법:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Win + I&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 키를 눌러 &lt;/span&gt;&lt;span&gt;&lt;b&gt;설정&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 엽니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Windows 업데이트&lt;/b&gt;&lt;/span&gt;&lt;span&gt;로 이동합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&quot;업데이트 확인&quot;을 클릭한 후, 최신 업데이트를 설치합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;업데이트 후에는 반드시 &lt;/span&gt;&lt;span&gt;&lt;b&gt;컴퓨터를 재부팅&lt;/b&gt;&lt;/span&gt;&lt;span&gt;해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;4) 시스템 파일 검사 실행하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;파일 탐색기 오류는 손상된 시스템 파일 때문일 수도 있습니다. **SFC(시스템 파일 검사기)**를 실행하여 손상된 파일을 복구해 보세요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;방법:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Win + S&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 눌러 &quot;CMD&quot;를 검색한 후, 마우스 오른쪽 버튼을 클릭하고 &lt;/span&gt;&lt;span&gt;&lt;b&gt;관리자 권한으로 실행&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 선택합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;명령 프롬프트 창에서 아래 명령어를 입력하고 Enter를 누릅니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;sfc /scannow&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;검사가 완료될 때까지 기다린 후 컴퓨터를 다시 시작합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 과정은 시간이 걸릴 수 있지만, 파일 탐색기 오류 해결에 매우 효과적입니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;✅ &lt;/span&gt;&lt;span&gt;&lt;b&gt;5) 레지스트리 키 삭제&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;탐색기 실행은 잘 되는데 드라이브 하위 선택시 응답이 없을때는 폴더에 대한 정보가 충돌일 가능성이 높습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;탐색기 관련 레지스트리 키를 삭제하여&amp;nbsp; 해결할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;방법:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;레지스트 편집 &lt;/b&gt;(Win + R) &amp;rarr; &lt;b&gt;Regedit 를 입력 실행&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;&lt;span&gt;이동 : &lt;span style=&quot;background-color: #ffffff; color: #404040; text-align: start;&quot;&gt;\ HKEY_CURRENT_USER \ Software \ Classes \ Local Settings \ Software \ Microsoft \ Windows \ Shell&lt;/span&gt; &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Shell 하위 키를 모두 삭제 후, 파일 탐색기를 실행해봅니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;3. 결론 (Conclusion)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지금까지 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Windows 10, 11에서 파일 탐색기 오류 해결방법&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 살펴봤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;✔ 파일 탐색기를 &lt;/span&gt;&lt;span&gt;&lt;b&gt;다시 시작&lt;/b&gt;&lt;/span&gt;&lt;span&gt;하거나 &lt;/span&gt;&lt;span&gt;&lt;b&gt;설정을 초기화&lt;/b&gt;&lt;/span&gt;&lt;span&gt;하는 간단한 방법부터, ✔ &lt;/span&gt;&lt;span&gt;&lt;b&gt;Windows 업데이트&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&lt;b&gt;시스템 파일 검사&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&lt;b&gt;새 사용자 계정 생성&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 등 다양한 해결책을 적용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;위 방법들을 하나씩 시도해보면서 문제를 해결해 보세요. 만약 해결되지 않는다면, &lt;/span&gt;&lt;span&gt;&lt;b&gt;Windows 포럼이나 고객센터&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 통해 추가적인 도움을 받을 수도 있습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>OS/Window</category>
      <category>file explorer error</category>
      <category>file explorer exception</category>
      <category>windows file explorer</category>
      <category>윈도우 탐색기</category>
      <category>탐색기 오류</category>
      <category>탐색기 오류 해결</category>
      <category>탐색기 오류 해결방법</category>
      <category>탐색기 충돌</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/10</guid>
      <comments>https://neorc.tistory.com/10#entry10comment</comments>
      <pubDate>Fri, 28 Feb 2025 13:39:15 +0900</pubDate>
    </item>
    <item>
      <title>[Java] HttpURLConnection으로 HTTP/HTTPS 연결 구현하기</title>
      <link>https://neorc.tistory.com/9</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; JDK에 기본으로 포함된 HttpURLConnection 클래스만으로도 충분히 HTTP와 HTTPS 연결을 구현할 수 있다는 사실을 알고 계셨나요? 복잡한 외부 의존성 없이 순수 자바로 HTTP/HTTPS 연결을 구현하는 방법을 알아보겠습니다. &lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1.&amp;nbsp;[HttpURLConnection&amp;nbsp;vs&amp;nbsp;외부&amp;nbsp;라이브러리](#httpurlconnection-vs-외부-라이브러리) &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2.&amp;nbsp;[HTTP&amp;nbsp;GET&amp;nbsp;요청&amp;nbsp;구현&amp;nbsp;(파라미터&amp;nbsp;포함)](#http-get-요청-구현) &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3.&amp;nbsp;[HTTP&amp;nbsp;POST&amp;nbsp;요청&amp;nbsp;구현&amp;nbsp;(JSON&amp;nbsp;데이터&amp;nbsp;전송)](#http-post-요청-구현) &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;4.&amp;nbsp;[HTTPS&amp;nbsp;연결&amp;nbsp;시&amp;nbsp;자주&amp;nbsp;발생하는&amp;nbsp;문제와&amp;nbsp;해결법](#https-연결-시-자주-발생하는-문제와-해결법) &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;5.&amp;nbsp;[타임아웃&amp;nbsp;설정과&amp;nbsp;성능&amp;nbsp;최적화](#타임아웃-설정과-성능-최적화) &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;6.&amp;nbsp;[자주&amp;nbsp;묻는&amp;nbsp;질문(FAQ)](#자주-묻는-질문)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HttpURLConnection vs 외부 라이브러리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;왜 HttpURLConnection을 사용해야 할까요?&quot; 많은 개발자들이 가장 먼저 던지는 질문입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HttpURLConnection의 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;별도의 의존성 추가 필요 없음&lt;/b&gt; - JDK에 기본 내장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가벼운 메모리 사용량&lt;/b&gt; - 외부 라이브러리보다 리소스 사용이 적음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단순한 HTTP 요청에 적합&lt;/b&gt; - 간단한 API 호출에 불필요한 오버헤드 제거&lt;/li&gt;
&lt;li&gt;&lt;b&gt;레거시 시스템 호환성&lt;/b&gt; - 오래된 자바 버전에서도 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;외부 라이브러리(OkHttp, Apache HttpClient 등)가 더 나은 경우&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡한 HTTP 요청이 많은 경우&lt;/li&gt;
&lt;li&gt;동시에 많은 연결을 처리해야 하는 경우&lt;/li&gt;
&lt;li&gt;고급 기능(캐싱, 쿠키 관리 등)이 필요한 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HTTP GET 요청 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 가장 많이 사용되는 GET 요청 구현 방법을 살펴보겠습니다. 특히 URL 파라미터를 포함한 요청 방법에 초점을 맞추겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1740554624337&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class HttpGetExample {
    
    public static void main(String[] args) {
        try {
            // 파라미터 준비
            Map&amp;lt;String, String&amp;gt; parameters = new HashMap&amp;lt;&amp;gt;();
            parameters.put(&quot;name&quot;, &quot;홍길동&quot;);
            parameters.put(&quot;age&quot;, &quot;30&quot;);
            parameters.put(&quot;query&quot;, &quot;자바 프로그래밍&quot;);
            
            // 파라미터가 포함된 URL 생성
            String baseUrl = &quot;http://example.com/api/search&quot;;
            StringBuilder urlBuilder = new StringBuilder(baseUrl);
            urlBuilder.append(&quot;?&quot;);
            
            boolean first = true;
            for (Map.Entry&amp;lt;String, String&amp;gt; entry : parameters.entrySet()) {
                if (!first) {
                    urlBuilder.append(&quot;&amp;amp;&quot;);
                }
                urlBuilder.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.toString()));
                urlBuilder.append(&quot;=&quot;);
                urlBuilder.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.toString()));
                first = false;
            }
            
            // URL 객체 생성
            URL url = new URL(urlBuilder.toString());
            
            // HttpURLConnection 객체 생성
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            
            // 요청 메소드 설정
            connection.setRequestMethod(&quot;GET&quot;);
            
            // 타임아웃 설정 - 실무에서 중요!
            connection.setConnectTimeout(5000); // 연결 타임아웃 5초
            connection.setReadTimeout(5000);    // 읽기 타임아웃 5초
            
            // 요청 헤더 설정
            connection.setRequestProperty(&quot;Accept&quot;, &quot;application/json&quot;);
            connection.setRequestProperty(&quot;User-Agent&quot;, &quot;Mozilla/5.0&quot;);  // 일부 서버는 User-Agent를 요구함
            
            // 응답 코드 확인
            int responseCode = connection.getResponseCode();
            System.out.println(&quot;응답 코드: &quot; + responseCode);
            
            // 응답 읽기
            try (BufferedReader in = new BufferedReader(
                    new InputStreamReader(connection.getInputStream()))) {
                String line;
                StringBuilder response = new StringBuilder();
                
                while ((line = in.readLine()) != null) {
                    response.append(line);
                }
                
                System.out.println(&quot;응답 내용: &quot; + response.toString());
            }
            
            // 연결 종료
            connection.disconnect();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실무 팁: GET 요청 시 주의사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;항상 파라미터를 URL 인코딩하세요&lt;/b&gt; - 특수문자나 한글이 포함된 경우 반드시 필요&lt;/li&gt;
&lt;li&gt;&lt;b&gt;User-Agent 헤더 설정&lt;/b&gt; - 일부 서버는 봇 요청을 차단하므로 브라우저처럼 보이게 설정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;try-with-resources 사용&lt;/b&gt; - 자원 누수를 방지하기 위해 자동 닫기 활용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응답 인코딩 확인&lt;/b&gt; - 서버 응답의 문자 인코딩이 UTF-8인지 확인하고 적절히 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HTTP POST 요청 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST API 연동 시 가장 많이 사용되는 JSON 데이터 전송을 위한 POST 요청 구현 방법입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1740554643410&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public class HttpPostExample {
    
    public static void main(String[] args) {
        try {
            // URL 객체 생성
            URL url = new URL(&quot;http://example.com/api/users&quot;);
            
            // HttpURLConnection 객체 생성
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            
            // 요청 메소드 설정
            connection.setRequestMethod(&quot;POST&quot;);
            
            // 출력 스트림 활성화 (POST 데이터 전송을 위해 필요)
            connection.setDoOutput(true);
            
            // 타임아웃 설정
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(5000);
            
            // 요청 헤더 설정
            connection.setRequestProperty(&quot;Content-Type&quot;, &quot;application/json; charset=UTF-8&quot;);
            connection.setRequestProperty(&quot;Accept&quot;, &quot;application/json&quot;);
            
            // JSON 데이터 준비
            String jsonInputString = &quot;{&quot;
                + &quot;\&quot;name\&quot;: \&quot;홍길동\&quot;,&quot;
                + &quot;\&quot;email\&quot;: \&quot;hong@example.com\&quot;,&quot;
                + &quot;\&quot;age\&quot;: 30,&quot;
                + &quot;\&quot;address\&quot;: {&quot;
                + &quot;  \&quot;city\&quot;: \&quot;서울\&quot;,&quot;
                + &quot;  \&quot;zipcode\&quot;: \&quot;12345\&quot;&quot;
                + &quot;}&quot;
                + &quot;}&quot;;
            
            // POST 데이터 전송
            try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) {
                byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
                wr.write(input, 0, input.length);
            }
            
            // 응답 코드 확인
            int responseCode = connection.getResponseCode();
            System.out.println(&quot;응답 코드: &quot; + responseCode);
            
            // 정상 응답과 에러 응답을 구분하여 처리 - 실무에서 매우 중요!
            if (responseCode &amp;gt;= 200 &amp;amp;&amp;amp; responseCode &amp;lt; 300) {  // 성공 응답
                try (BufferedReader br = new BufferedReader(
                        new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
                    String line;
                    StringBuilder response = new StringBuilder();
                    while ((line = br.readLine()) != null) {
                        response.append(line);
                    }
                    System.out.println(&quot;성공 응답: &quot; + response.toString());
                }
            } else {  // 에러 응답
                try (BufferedReader br = new BufferedReader(
                        new InputStreamReader(connection.getErrorStream(), StandardCharsets.UTF_8))) {
                    String line;
                    StringBuilder response = new StringBuilder();
                    while ((line = br.readLine()) != null) {
                        response.append(line);
                    }
                    System.out.println(&quot;에러 응답: &quot; + response.toString());
                }
            }
            
            // 연결 종료
            connection.disconnect();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실무 팁: POST 요청 시 주의사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;반드시 setDoOutput(true) 설정&lt;/b&gt; - POST 데이터 전송에 필수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정확한 Content-Type 헤더 설정&lt;/b&gt; - 특히 JSON 데이터 전송 시 application/json; charset=UTF-8 필수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;에러 응답 처리&lt;/b&gt; - 상태 코드에 따라 getInputStream() 또는 getErrorStream()을 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;try-with-resources 사용&lt;/b&gt; - 모든 스트림을 안전하게 닫기&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HTTPS 연결 시 자주 발생하는 문제와 해결법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTPS 연결 시 개발자들이 자주 겪는 인증서 관련 문제와 해결 방법을 알아보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1740554663062&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyStore;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class HttpsExample {
    
    public static void main(String[] args) {
        try {
            // 1. 기본 HTTPS 요청 (대부분의 공개 API에 적합)
            URL url = new URL(&quot;https://api.github.com/users/octocat&quot;);
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
            
            connection.setRequestMethod(&quot;GET&quot;);
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(5000);
            
            int responseCode = connection.getResponseCode();
            System.out.println(&quot;응답 코드: &quot; + responseCode);
            
            // 응답 읽기
            if (responseCode == HttpsURLConnection.HTTP_OK) {
                try (BufferedReader in = new BufferedReader(
                        new InputStreamReader(connection.getInputStream()))) {
                    String line;
                    StringBuilder response = new StringBuilder();
                    while ((line = in.readLine()) != null) {
                        response.append(line);
                    }
                    System.out.println(&quot;응답 내용: &quot; + response.toString());
                }
            }
            
            // 연결 종료
            connection.disconnect();
            
        } catch (Exception e) {
            System.out.println(&quot;HTTPS 연결 오류: &quot; + e.getMessage());
            e.printStackTrace();
            
            // 오류 해결 가이드 제공
            if (e.getMessage().contains(&quot;PKIX path building failed&quot;) || 
                e.getMessage().contains(&quot;unable to find valid certification path&quot;)) {
                System.out.println(&quot;\n[인증서 오류 해결 방법]&quot;);
                System.out.println(&quot;1. 서버의 인증서를 Java 키스토어에 추가하세요:&quot;);
                System.out.println(&quot;   $ keytool -import -alias example -keystore $JAVA_HOME/lib/security/cacerts -file server.crt&quot;);
                System.out.println(&quot;2. 또는 개발/테스트용으로만 인증서 검증을 비활성화하는 코드를 사용하세요 (프로덕션 환경에서는 권장하지 않음)&quot;);
            }
        }
    }
    
    // 개발 환경에서만 사용할 인증서 검증 비활성화 메소드 (보안 위험이 있으므로 프로덕션에서는 사용하지 마세요!)
    private static void disableCertificateValidation() throws Exception {
        // 모든 인증서를 신뢰하는 TrustManager 생성
        TrustManager[] trustAllCerts = new TrustManager[] {
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() { return null; }
                public void checkClientTrusted(X509Certificate[] certs, String authType) { }
                public void checkServerTrusted(X509Certificate[] certs, String authType) { }
            }
        };
        
        // SSL 컨텍스트 설정
        SSLContext sc = SSLContext.getInstance(&quot;TLS&quot;);
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        
        // 호스트명 검증 비활성화
        HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -&amp;gt; true);
    }
    
    // 프로덕션 환경에서 사용할 사용자 정의 키스토어 설정 메소드
    private static void setupCustomTrustStore(String trustStorePath, String trustStorePassword) throws Exception {
        System.setProperty(&quot;javax.net.ssl.trustStore&quot;, trustStorePath);
        System.setProperty(&quot;javax.net.ssl.trustStorePassword&quot;, trustStorePassword);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HTTPS 연결 문제 해결 가이드&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. &quot;PKIX path building failed&quot; 오류 해결&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 오류는 서버의 SSL 인증서를 Java가 신뢰하지 않을 때 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결 방법:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;프로덕션 환경:&lt;/b&gt; 서버 인증서를 Java 키스토어에 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1740554686657&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;keytool -import -alias example -keystore $JAVA_HOME/lib/security/cacerts -file server.crt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;개발/테스트 환경:&lt;/b&gt; Java 시스템 속성 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1740554775064&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;System.setProperty(&quot;javax.net.ssl.trustStore&quot;, &quot;path/to/custom/truststore&quot;); 
System.setProperty(&quot;javax.net.ssl.trustStorePassword&quot;, &quot;password&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. &quot;Hostname verification failed&quot; 오류 해결&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 오류는 인증서의 도메인명과 실제 접속 URL의 도메인명이 일치하지 않을 때 발생합니다.&lt;/p&gt;
&lt;p 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-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;올바른 도메인명으로 접속하거나&lt;/li&gt;
&lt;li&gt;개발/테스트 환경에서는 호스트명 검증 비활성화 (프로덕션에서는 권장하지 않음)
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1740554816652&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -&amp;gt; true);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;타임아웃 설정과 성능 최적화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 HTTP 요청의 성능과 안정성을 높이기 위한 타임아웃 설정 방법과 성능 최적화 팁을 알아보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1740554827596&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.net.HttpURLConnection;
import java.net.URL;

public class HttpOptimizationExample {
    
    public static void main(String[] args) {
        HttpURLConnection connection = null;
        
        try {
            URL url = new URL(&quot;http://example.com/api/resource&quot;);
            connection = (HttpURLConnection) url.openConnection();
            
            // 1. 기본 설정
            connection.setRequestMethod(&quot;GET&quot;);
            
            // 2. 타임아웃 설정 - 실무에서 매우 중요
            connection.setConnectTimeout(3000);  // 연결 타임아웃: 3초
            connection.setReadTimeout(10000);    // 읽기 타임아웃: 10초
            
            // 3. 캐싱 비활성화 (항상 최신 데이터 필요 시)
            connection.setUseCaches(false);
            
            // 4. 리다이렉션 자동 처리 (필요 시)
            connection.setInstanceFollowRedirects(true);
            
            // 5. Keep-Alive 설정 (연결 재사용)
            connection.setRequestProperty(&quot;Connection&quot;, &quot;keep-alive&quot;);
            
            // 6. Gzip 압축 지원 (대용량 데이터 처리 시 효율적)
            connection.setRequestProperty(&quot;Accept-Encoding&quot;, &quot;gzip, deflate&quot;);
            
            // 7. 응답 코드 확인
            int responseCode = connection.getResponseCode();
            System.out.println(&quot;응답 코드: &quot; + responseCode);
            
            // 응답 처리 (생략)...
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 항상 연결 종료
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;성능 최적화 팁&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&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&gt;연결 타임아웃(connectTimeout): 일반적으로 3-5초&lt;/li&gt;
&lt;li&gt;읽기 타임아웃(readTimeout): 응답 크기에 따라 10-30초&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연결 재사용(Connection Pooling)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HttpURLConnection은 기본적으로 연결 풀링을 지원하지 않음&lt;/li&gt;
&lt;li&gt;대량의 요청이 필요한 경우 Apache HttpClient나 OkHttp 같은 라이브러리 고려&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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&gt;Accept-Encoding: gzip, deflate 헤더 추가&lt;/li&gt;
&lt;li&gt;응답 처리 시 GZIPInputStream을 통해 압축 해제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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&gt;다수의 요청을 병렬로 처리하려면 ExecutorService 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1740554849740&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ExecutorService executor = Executors.newFixedThreadPool(10);
List&amp;lt;Future&amp;lt;String&amp;gt;&amp;gt; futures = new ArrayList&amp;lt;&amp;gt;();

for (String apiUrl : urls) {
    futures.add(executor.submit(() -&amp;gt; sendHttpRequest(apiUrl)));
}

for (Future&amp;lt;String&amp;gt; future : futures) {
    String response = future.get();  // 응답 처리
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;자주 묻는 질문&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q1: HttpURLConnection과 HttpsURLConnection의 차이점은 무엇인가요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;A:&lt;/b&gt; HttpsURLConnection은 HttpURLConnection의 서브클래스로, SSL/TLS를 통한 보안 연결을 지원합니다. 기본 사용법은 동일하지만, HttpsURLConnection은 인증서 검증과 같은 추가 보안 기능을 제공합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q2: HttpURLConnection으로 파일을 업로드하는 방법은?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;A:&lt;/b&gt; 멀티파트 폼 데이터(multipart/form-data)를 사용하여 파일을 업로드할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1740554873188&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String boundary = &quot;----WebKitFormBoundary&quot; + System.currentTimeMillis();
connection.setRequestProperty(&quot;Content-Type&quot;, &quot;multipart/form-data; boundary=&quot; + boundary);

try (OutputStream output = connection.getOutputStream();
     PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8), true)) {
    
    // 텍스트 파라미터 추가
    writer.append(&quot;--&quot; + boundary).append(&quot;\r\n&quot;);
    writer.append(&quot;Content-Disposition: form-data; name=\&quot;param\&quot;&quot;).append(&quot;\r\n&quot;);
    writer.append(&quot;\r\n&quot;);
    writer.append(&quot;value&quot;).append(&quot;\r\n&quot;);
    
    // 파일 파라미터 추가
    writer.append(&quot;--&quot; + boundary).append(&quot;\r\n&quot;);
    writer.append(&quot;Content-Disposition: form-data; name=\&quot;file\&quot;; filename=\&quot;file.txt\&quot;&quot;).append(&quot;\r\n&quot;);
    writer.append(&quot;Content-Type: text/plain&quot;).append(&quot;\r\n&quot;);
    writer.append(&quot;\r\n&quot;);
    writer.flush();
    
    // 파일 데이터 복사
    Files.copy(Paths.get(&quot;path/to/file.txt&quot;), output);
    output.flush();
    
    // 경계 종료
    writer.append(&quot;\r\n&quot;);
    writer.append(&quot;--&quot; + boundary + &quot;--&quot;).append(&quot;\r\n&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q3: 어떤 경우에 OkHttp나 Apache HttpClient 같은 외부 라이브러리를 사용하는 것이 좋을까요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;A:&lt;/b&gt; 다음과 같은 경우 외부 라이브러리 사용을 고려하세요:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자동 연결 풀링이 필요한 경우&lt;/li&gt;
&lt;li&gt;복잡한 인증 메커니즘(OAuth 등)이 필요한 경우&lt;/li&gt;
&lt;li&gt;재시도 로직, 인터셉터 등 고급 기능이 필요한 경우&lt;/li&gt;
&lt;li&gt;비동기/동시 요청이 많은 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q4: HTTP 상태 코드를 어떻게 효과적으로 처리해야 할까요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;A:&lt;/b&gt; 상태 코드 범위별로 처리하는 것이 좋습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2xx (성공): 정상 응답 처리&lt;/li&gt;
&lt;li&gt;3xx (리다이렉션): 필요시 새 위치로 요청 재시도&lt;/li&gt;
&lt;li&gt;4xx (클라이언트 오류): 요청 수정 필요 (잘못된 인증, 권한 등)&lt;/li&gt;
&lt;li&gt;5xx (서버 오류): 일정 시간 후 재시도 로직 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q5: HttpURLConnection의 성능을 개선하는 방법은?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;A:&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;요청 간 Connection: keep-alive 헤더를 사용하여 연결 재사용&lt;/li&gt;
&lt;li&gt;큰 응답을 처리할 때는 버퍼 크기 조정 (기본 8KB)&lt;/li&gt;
&lt;li&gt;압축(gzip) 지원 활성화&lt;/li&gt;
&lt;li&gt;응답 처리 시 BufferedReader/BufferedInputStream 사용&lt;/li&gt;
&lt;li&gt;가능하면 ExecutorService를 사용하여 병렬 요청 처리&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바의 HttpURLConnection은 외부 라이브러리 없이도 충분히 강력한 HTTP/HTTPS 통신을 구현할 수 있는 클래스입니다. 이 글에서 다룬 샘플 코드와 팁을 활용하면 대부분의 일반적인 API 통신을 구현할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 요구사항이나 대규모 애플리케이션에서는 OkHttp, Apache HttpClient 같은 전문 라이브러리를 고려해볼 수도 있지만, 간단한 HTTP 요청이나 외부 의존성을 최소화하고 싶은 경우 HttpURLConnection은 여전히 훌륭한 선택입니다.&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <category>HTTP</category>
      <category>HTTP 상태 코드</category>
      <category>HttpClient</category>
      <category>https</category>
      <category>httpsurlconnection</category>
      <category>httpurlconnection</category>
      <category>java</category>
      <category>json 데이터 전송</category>
      <category>Keep-Alive</category>
      <category>자바</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/9</guid>
      <comments>https://neorc.tistory.com/9#entry9comment</comments>
      <pubDate>Wed, 26 Feb 2025 16:30:47 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Rest API 연결 가이드 샘플</title>
      <link>https://neorc.tistory.com/8</link>
      <description>&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;163&quot; data-end=&quot;206&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-start=&quot;213&quot; data-end=&quot;245&quot;&gt; &amp;nbsp;&lt;b&gt;Rest API 연결&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-pm-slice=&quot;3 2 []&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Http, Https 프로토콜 타입별로 처리&lt;/li&gt;
&lt;li&gt;&lt;span&gt;HttpURLConnection 연결에 대해 가이드 샘플 &lt;/span&gt;&lt;span&gt;구성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-start=&quot;427&quot; data-end=&quot;451&quot;&gt;Rest Api Client&lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;537&quot; data-end=&quot;546&quot;&gt; &amp;nbsp;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;예제 코드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740551525819&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;

public class RestApiClient {
    public static String sendHttpRequest(String targetUrl, String method, String jsonBody) {
        StringBuilder response = new StringBuilder();
        HttpURLConnection conn = null;
        OutputStream os = null;
        BufferedReader br = null;
        
        try {
            URL url = new URL(targetUrl);
            
            if (targetUrl.startsWith(&quot;https&quot;)) {
                conn = (HttpsURLConnection) url.openConnection();
            } else {
                conn = (HttpURLConnection) url.openConnection();
            }
            
            conn.setRequestMethod(method);
            conn.setRequestProperty(&quot;Content-Type&quot;, &quot;application/json&quot;);
            conn.setDoOutput(true);
            
            if (jsonBody != null &amp;amp;&amp;amp; jsonBody.length() &amp;gt; 0) {
                os = conn.getOutputStream();
                os.write(jsonBody.getBytes(&quot;UTF-8&quot;));
            }
            
            int responseCode = conn.getResponseCode();
            System.out.println(&quot;HTTP Response Code: &quot; + responseCode);
            
            br = new BufferedReader(new InputStreamReader(conn.getInputStream(), &quot;UTF-8&quot;));
            String responseLine;
            while ((responseLine = br.readLine()) != null) {
                response.append(responseLine.trim());
            }
        } catch (IOException e) {
            System.err.println(&quot;HTTP 요청 중 오류 발생: &quot; + e.getMessage());
        } finally {
            try {
                if (os != null) os.close();
                if (br != null) br.close();
                if (conn != null) conn.disconnect();
            } catch (IOException e) {
                System.err.println(&quot;리소스 해제 중 오류 발생: &quot; + e.getMessage());
            }
        }
        return response.toString();
    }

    public static void main(String[] args) {
        String url = &quot;https://example.com/api&quot;;
        String method = &quot;POST&quot;;
        String jsonBody = &quot;{\&quot;message\&quot;:\&quot;Hello, API!\&quot;}&quot;;

        String response = sendHttpRequest(url, method, jsonBody);
        System.out.println(&quot;Response: &quot; + response);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;b&gt;출력 결과:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740551565021&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HTTP Response Code: 200
Response: {&quot;status&quot;:&quot;success&quot;,&quot;data&quot;:&quot;Hello, Client!&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;</description>
      <category>프로그램/Java</category>
      <category>HTTP</category>
      <category>https 연결</category>
      <category>httpurlconnection</category>
      <category>REST API</category>
      <category>rest api 연결</category>
      <category>restapi</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/8</guid>
      <comments>https://neorc.tistory.com/8#entry8comment</comments>
      <pubDate>Wed, 26 Feb 2025 15:44:31 +0900</pubDate>
    </item>
    <item>
      <title>양자컴퓨터란 무엇인가?</title>
      <link>https://neorc.tistory.com/5</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;양자컴퓨터(Quantum Computer)는 기존의 고전 컴퓨터와는 완전히 다른 방식으로 정보를 처리합니다. &lt;br /&gt;양자역학의 원리를 이용하기 때문에 더 빠르고 강력한 계산을 할 수 있습니다. &lt;br /&gt;양자컴퓨터의 핵심 원리를 설명하면 다음과 같습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;양자컴퓨터의 원리 &lt;/b&gt;&lt;/blockquote&gt;
&lt;blockquote data-end=&quot;172&quot; data-start=&quot;151&quot; data-ke-style=&quot;style2&quot;&gt;큐비트(Qubit)&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;335&quot; data-start=&quot;173&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;240&quot; data-start=&quot;173&quot;&gt;고전 컴퓨터는 **비트(Bit)**로 정보를 처리하며, 비트는 &lt;b&gt;0 또는 1&lt;/b&gt; 두 가지 상태만 가질 수 있습니다.&lt;/li&gt;
&lt;li data-end=&quot;335&quot; data-start=&quot;241&quot;&gt;양자컴퓨터의 기본 단위는 **큐비트(Qubit)**입니다. 큐비트는 &lt;b&gt;0과 1의 상태를 동시에 가질 수 있는 중첩(superposition) 상태&lt;/b&gt;를 형성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;344&quot; data-start=&quot;337&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;417&quot; data-start=&quot;345&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;375&quot; data-start=&quot;345&quot;&gt;고전 컴퓨터 &amp;rarr; 1비트는 &lt;b&gt;0 또는 1&lt;/b&gt;만 가능&lt;/li&gt;
&lt;li data-end=&quot;417&quot; data-start=&quot;376&quot;&gt;양자컴퓨터 &amp;rarr; 1 큐비트는 &lt;b&gt;0, 1, 0과 1의 중첩&lt;/b&gt; 상태 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;450&quot; data-start=&quot;419&quot; data-ke-size=&quot;size16&quot;&gt;이 중첩 덕분에 여러 계산을 동시에 수행할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;450&quot; data-start=&quot;419&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;485&quot; data-start=&quot;457&quot; data-ke-style=&quot;style2&quot;&gt;중첩(Superposition)&lt;/blockquote&gt;
&lt;p data-end=&quot;529&quot; data-start=&quot;486&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;529&quot; data-start=&quot;486&quot; data-ke-size=&quot;size16&quot;&gt;큐비트는 &lt;b&gt;여러 상태를 동시에 표현&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;529&quot; data-start=&quot;486&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;예시:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;655&quot; data-start=&quot;530&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;591&quot; data-start=&quot;530&quot;&gt;고전 컴퓨터가 2비트로 표현할 수 있는 상태: 00, 01, 10, 11 (각각 한 번에 하나의 상태)&lt;/li&gt;
&lt;li data-end=&quot;655&quot; data-start=&quot;592&quot;&gt;양자컴퓨터는 2 큐비트로 동시에 &lt;b&gt;모든 상태(00, 01, 10, 11)를 한 번에 계산&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;688&quot; data-start=&quot;657&quot; data-ke-size=&quot;size16&quot;&gt;이 때문에 &lt;b&gt;병렬 계산 능력&lt;/b&gt;이 엄청나게 뛰어납니다.&lt;/p&gt;
&lt;p data-end=&quot;688&quot; data-start=&quot;657&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;722&quot; data-start=&quot;695&quot; data-ke-style=&quot;style2&quot;&gt;얽힘(Entanglement)&lt;/blockquote&gt;
&lt;p data-end=&quot;847&quot; data-start=&quot;723&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;847&quot; data-start=&quot;723&quot; data-ke-size=&quot;size16&quot;&gt;양자 얽힘은 두 큐비트가 서로 강하게 연결되어 &lt;b&gt;한 큐비트의 상태가 다른 큐비트의 상태를 즉시 결정&lt;/b&gt;하는 현상입니다.&lt;br /&gt;이 얽힘을 이용하면 여러 큐비트 간의 &lt;b&gt;정보 전달과 계산이 빠르게 이루어질 수 있습니다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-end=&quot;847&quot; data-start=&quot;723&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;858&quot; data-start=&quot;849&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;920&quot; data-start=&quot;859&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;920&quot; data-start=&quot;859&quot;&gt;큐비트 A와 큐비트 B가 얽혀 있으면, 큐비트 A의 상태를 알면 B의 상태도 자동으로 알 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;969&quot; data-start=&quot;922&quot; data-ke-size=&quot;size16&quot;&gt;이 특성은 &lt;b&gt;암호 해독, 최적화 문제, 빅데이터 분석&lt;/b&gt;에서 큰 장점을 제공합니다.&lt;/p&gt;
&lt;p data-end=&quot;969&quot; data-start=&quot;922&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;1002&quot; data-start=&quot;976&quot; data-ke-style=&quot;style2&quot;&gt;측정(Measurement)&lt;/blockquote&gt;
&lt;p data-end=&quot;1112&quot; data-start=&quot;1003&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1112&quot; data-start=&quot;1003&quot; data-ke-size=&quot;size16&quot;&gt;큐비트는 중첩 상태에서 &lt;b&gt;측정&lt;/b&gt;할 때 &lt;b&gt;0 또는 1로 결과가 결정&lt;/b&gt;됩니다.&lt;br /&gt;즉, 중첩 상태로 여러 계산을 동시에 수행한 후, 최종적으로 &lt;b&gt;측정 시 하나의 결과&lt;/b&gt;만 얻을 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1112&quot; data-start=&quot;1003&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;1136&quot; data-start=&quot;1119&quot; data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;양자컴퓨터의 장점&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1273&quot; data-start=&quot;1137&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1185&quot; data-start=&quot;1137&quot;&gt;&lt;b&gt;초고속 계산&lt;/b&gt;: 기존 컴퓨터로 수천 년 걸릴 문제를 몇 초 만에 해결 가능&lt;/li&gt;
&lt;li data-end=&quot;1231&quot; data-start=&quot;1186&quot;&gt;&lt;b&gt;복잡한 문제 해결&lt;/b&gt;: 암호 해독, 약물 개발, 최적화 문제 등에 강력&lt;/li&gt;
&lt;li data-end=&quot;1273&quot; data-start=&quot;1232&quot;&gt;&lt;b&gt;에너지 효율적&lt;/b&gt;: 기존 슈퍼컴퓨터보다 훨씬 적은 에너지를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;1302&quot; data-start=&quot;1280&quot; data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;양자컴퓨터의 단점 및 한계&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1460&quot; data-start=&quot;1303&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1358&quot; data-start=&quot;1303&quot;&gt;&lt;b&gt;기술적 난제&lt;/b&gt;: 큐비트 유지(양자 얽힘 유지)가 어렵고, 작은 외부 자극에도 오류 발생&lt;/li&gt;
&lt;li data-end=&quot;1406&quot; data-start=&quot;1359&quot;&gt;&lt;b&gt;비싼 개발 비용&lt;/b&gt;: 안정적인 양자컴퓨터 개발에 막대한 비용과 연구가 필요&lt;/li&gt;
&lt;li data-end=&quot;1460&quot; data-start=&quot;1407&quot;&gt;&lt;b&gt;현재는 초기 단계&lt;/b&gt;: 상용화된 양자컴퓨터는 아직 제한적이며, 특정 분야에만 적용 중&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양자컴퓨터가 완전히 상용화된다면 &lt;b&gt;기존 컴퓨터로 풀 수 없는 복잡한 문제&lt;/b&gt;를 빠르게 해결할 수 있어 &lt;b&gt;AI, 의료, 암호학, 금융&lt;/b&gt; 등 다양한 분야에 혁신을 가져올 것으로 기대됩니다.&lt;/p&gt;</description>
      <category>과학/양자컴퓨터</category>
      <category>양자원리</category>
      <category>양자컴퓨터</category>
      <category>양자컴퓨터 장단점</category>
      <category>얽힘</category>
      <category>중첩</category>
      <category>큐비트</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/5</guid>
      <comments>https://neorc.tistory.com/5#entry5comment</comments>
      <pubDate>Tue, 25 Feb 2025 17:12:07 +0900</pubDate>
    </item>
    <item>
      <title>예쁜꼬마선충의 신경 연결 지도를 활용하여 로봇에 인공지능(AI) 프로그램</title>
      <link>https://neorc.tistory.com/4</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt; 예쁜꼬마선충의 신경 연결 지도를 활용하여 로봇에 인공지능(AI) 프로그램을 개발하려면, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;신경 연결 지도(connectome)를 기반으로 로봇의 의사결정을 제어하는 시뮬레이션을 설계할 수 있습니다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;아래는 이를 자바로 구현한 예제입니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;144&quot; data-start=&quot;133&quot; data-ke-style=&quot;style2&quot;&gt;프로그램 개요&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;320&quot; data-start=&quot;145&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;206&quot; data-start=&quot;145&quot;&gt;&lt;b&gt;신경 연결 지도 모델링&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;206&quot; data-start=&quot;169&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;206&quot; data-start=&quot;169&quot;&gt;예쁜꼬마선충의 신경 세포(노드)와 연결(엣지)을 그래프로 표현.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;262&quot; data-start=&quot;207&quot;&gt;&lt;b&gt;로봇 행동 모델링&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;262&quot; data-start=&quot;228&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;262&quot; data-start=&quot;228&quot;&gt;신경 연결 지도를 통해 입력(센서)과 출력(행동)을 연결.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;320&quot; data-start=&quot;263&quot;&gt;&lt;b&gt;AI 제어 로직&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;320&quot; data-start=&quot;283&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;320&quot; data-start=&quot;283&quot;&gt;입력 신호를 기반으로 신경 네트워크를 통해 로봇의 행동을 결정.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-end=&quot;352&quot; data-start=&quot;322&quot; data-ke-style=&quot;style2&quot;&gt;자바 코드: 신경 연결 지도 기반 로봇 프로그램&lt;/blockquote&gt;
&lt;pre id=&quot;code_1740468734045&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

public class WormAI {

    // 신경 세포 클래스 (노드)
    static class Neuron {
        String name;
        double activation; // 활성화 값 (0~1)

        Neuron(String name) {
            this.name = name;
            this.activation = 0.0;
        }

        @Override
        public String toString() {
            return name + &quot; (Activation: &quot; + activation + &quot;)&quot;;
        }
    }

    // 신경 연결 지도 클래스 (그래프)
    static class NeuralConnectome {
        private Map&amp;lt;Neuron, List&amp;lt;Neuron&amp;gt;&amp;gt; connections;
        private Map&amp;lt;String, Neuron&amp;gt; neuronMap;

        NeuralConnectome() {
            connections = new HashMap&amp;lt;&amp;gt;();
            neuronMap = new HashMap&amp;lt;&amp;gt;();
        }

        // 신경 세포 추가
        public void addNeuron(String name) {
            Neuron neuron = new Neuron(name);
            connections.put(neuron, new ArrayList&amp;lt;&amp;gt;());
            neuronMap.put(name, neuron);
        }

        // 신경 연결 추가
        public void addConnection(String from, String to) {
            Neuron fromNeuron = neuronMap.get(from);
            Neuron toNeuron = neuronMap.get(to);
            if (fromNeuron != null &amp;amp;&amp;amp; toNeuron != null) {
                connections.get(fromNeuron).add(toNeuron);
            }
        }

        // 신경 활성화 전파
        public void propagateSignal(String inputNeuron, double signalStrength) {
            Neuron neuron = neuronMap.get(inputNeuron);
            if (neuron != null) {
                activateNeuron(neuron, signalStrength);
            }
        }

        // 특정 신경 세포 활성화 및 전파
        private void activateNeuron(Neuron neuron, double signalStrength) {
            if (neuron.activation &amp;lt; signalStrength) {
                neuron.activation = signalStrength;
                for (Neuron connectedNeuron : connections.get(neuron)) {
                    activateNeuron(connectedNeuron, signalStrength * 0.8); // 감쇠율 적용
                }
            }
        }

        // 신경 세포 출력 상태 확인
        public void printNeuralState() {
            for (Neuron neuron : neuronMap.values()) {
                System.out.println(neuron);
            }
        }

        // 특정 신경 세포 찾기
        public Neuron getNeuron(String name) {
            return neuronMap.get(name);
        }
    }

    // 로봇 클래스
    static class Robot {
        private NeuralConnectome connectome;

        Robot(NeuralConnectome connectome) {
            this.connectome = connectome;
        }

        // 로봇의 행동 결정
        public void act() {
            Neuron motorNeuron = connectome.getNeuron(&quot;Motor&quot;);
            if (motorNeuron != null &amp;amp;&amp;amp; motorNeuron.activation &amp;gt; 0.5) {
                System.out.println(&quot;Robot is moving forward.&quot;);
            } else {
                System.out.println(&quot;Robot is idle.&quot;);
            }
        }
    }

    public static void main(String[] args) {
        // 신경 연결 지도 생성
        NeuralConnectome connectome = new NeuralConnectome();

        // 신경 세포 추가 (예시 데이터)
        connectome.addNeuron(&quot;Sensor&quot;);
        connectome.addNeuron(&quot;Interneuron&quot;);
        connectome.addNeuron(&quot;Motor&quot;);

        // 신경 연결 추가 (예시 데이터)
        connectome.addConnection(&quot;Sensor&quot;, &quot;Interneuron&quot;);
        connectome.addConnection(&quot;Interneuron&quot;, &quot;Motor&quot;);

        // 로봇 생성
        Robot robot = new Robot(connectome);

        // 신경 신호 입력
        System.out.println(&quot;Sensor activated with signal strength 1.0.&quot;);
        connectome.propagateSignal(&quot;Sensor&quot;, 1.0);

        // 신경 상태 출력
        System.out.println(&quot;\nNeural state:&quot;);
        connectome.printNeuralState();

        // 로봇의 행동 결정
        System.out.println(&quot;\nRobot action:&quot;);
        robot.act();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;3987&quot; data-start=&quot;3978&quot; data-ke-style=&quot;style2&quot;&gt;코드 설명&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;4341&quot; data-start=&quot;3988&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;4058&quot; data-start=&quot;3988&quot;&gt;&lt;b&gt;Neuron 클래스&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4058&quot; data-start=&quot;4012&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4058&quot; data-start=&quot;4012&quot;&gt;신경 세포를 나타냅니다. 각 신경 세포는 이름과 활성화 값(0~1)을 가집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;4165&quot; data-start=&quot;4060&quot;&gt;&lt;b&gt;NeuralConnectome 클래스&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4165&quot; data-start=&quot;4094&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4118&quot; data-start=&quot;4094&quot;&gt;신경 연결 지도를 그래프로 모델링합니다.&lt;/li&gt;
&lt;li data-end=&quot;4165&quot; data-start=&quot;4122&quot;&gt;신경 세포 간 연결을 저장하고, 입력 신호를 기반으로 활성화를 전파합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;4262&quot; data-start=&quot;4167&quot;&gt;&lt;b&gt;Robot 클래스&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4262&quot; data-start=&quot;4190&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4217&quot; data-start=&quot;4190&quot;&gt;신경 연결 지도를 기반으로 행동을 결정합니다.&lt;/li&gt;
&lt;li data-end=&quot;4262&quot; data-start=&quot;4221&quot;&gt;Motor 뉴런의 활성화 값을 기준으로 로봇의 움직임을 결정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;4341&quot; data-start=&quot;4264&quot;&gt;&lt;b&gt;main 메서드&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4341&quot; data-start=&quot;4286&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4305&quot; data-start=&quot;4286&quot;&gt;신경 세포와 연결을 설정합니다.&lt;/li&gt;
&lt;li data-end=&quot;4341&quot; data-start=&quot;4309&quot;&gt;입력 신호를 시뮬레이션하고, 로봇의 행동을 출력합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;실행 결과 (예시)&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IYoue/btsMxBLUKIQ/Ujb2TcYtTSr0NjA5crkFzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IYoue/btsMxBLUKIQ/Ujb2TcYtTSr0NjA5crkFzK/img.png&quot; data-alt=&quot;로봇에 인공지능(AI) 프로그램 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IYoue/btsMxBLUKIQ/Ujb2TcYtTSr0NjA5crkFzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIYoue%2FbtsMxBLUKIQ%2FUjb2TcYtTSr0NjA5crkFzK%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;597&quot; height=&quot;231&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;로봇에 인공지능(AI) 프로그램 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;4555&quot; data-start=&quot;4545&quot; data-ke-style=&quot;style2&quot;&gt;확장 가능성&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;4799&quot; data-start=&quot;4556&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;4624&quot; data-start=&quot;4556&quot;&gt;&lt;b&gt;실제 센서 데이터 통합&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4624&quot; data-start=&quot;4580&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4624&quot; data-start=&quot;4580&quot;&gt;초음파 센서, 적외선 센서 등 실제 로봇 하드웨어의 데이터를 입력으로 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;4677&quot; data-start=&quot;4625&quot;&gt;&lt;b&gt;신경망 강화&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4677&quot; data-start=&quot;4643&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4677&quot; data-start=&quot;4643&quot;&gt;더 많은 신경 세포와 연결을 추가하여 복잡한 행동 모델링.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;4737&quot; data-start=&quot;4678&quot;&gt;&lt;b&gt;학습 알고리즘 통합&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4737&quot; data-start=&quot;4700&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4737&quot; data-start=&quot;4700&quot;&gt;강화 학습을 추가하여 로봇이 환경에서 학습하고 적응하도록 설계.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;4799&quot; data-start=&quot;4738&quot;&gt;&lt;b&gt;GUI 시뮬레이션&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4799&quot; data-start=&quot;4759&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4799&quot; data-start=&quot;4759&quot;&gt;신경 상태와 로봇 행동을 시각적으로 표현하는 사용자 인터페이스 추가.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>프로그램/Java</category>
      <category>로봇</category>
      <category>신경지도</category>
      <category>예쁜꼬마선충</category>
      <category>의사결정</category>
      <category>인공지능</category>
      <category>자바 연결지도</category>
      <category>자바 인공지능</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/4</guid>
      <comments>https://neorc.tistory.com/4#entry4comment</comments>
      <pubDate>Tue, 25 Feb 2025 16:37:39 +0900</pubDate>
    </item>
    <item>
      <title>예쁜꼬마선충 뇌정보를 이해하고 이용한 Java 프로그램</title>
      <link>https://neorc.tistory.com/3</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;예쁜꼬마선충(Caenorhabditis elegans, C. elegans)는 신경과학 연구에서 중요한 모델 생물로, &lt;br /&gt;특히 뇌와 신경계 구조에 대한 정보가 매우 잘 정리되어 있습니다. 주요 특징은 다음과 같습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;143&quot; data-start=&quot;125&quot; data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;신경계의 크기&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;251&quot; data-start=&quot;144&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;197&quot; data-start=&quot;144&quot;&gt;예쁜꼬마선충은 신경계가 단순하여 **총 302개의 신경세포(neurons)**로 구성됩니다.&lt;/li&gt;
&lt;li data-end=&quot;251&quot; data-start=&quot;198&quot;&gt;신경세포 간 연결은 **7,000개 정도의 시냅스(synapses)**로 이루어져 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;270&quot; data-start=&quot;253&quot; data-ke-size=&quot;size23&quot;&gt;2. &lt;b&gt;신경계 구조&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;450&quot; data-start=&quot;271&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;338&quot; data-start=&quot;271&quot;&gt;&lt;b&gt;머리 신경절&lt;/b&gt;(Head ganglia): 주된 신경세포들이 모여 있는 영역으로, 주요 감각과 운동을 조절합니다.&lt;/li&gt;
&lt;li data-end=&quot;396&quot; data-start=&quot;339&quot;&gt;&lt;b&gt;몸 신경절&lt;/b&gt;(Body ganglia): 몸 전체에 분포하며 근육과 연결되어 운동을 제어합니다.&lt;/li&gt;
&lt;li data-end=&quot;450&quot; data-start=&quot;397&quot;&gt;&lt;b&gt;꼬리 신경절&lt;/b&gt;(Tail ganglia): 꼬리 부분에서 감각과 운동 신호를 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;484&quot; data-start=&quot;452&quot; data-ke-size=&quot;size23&quot;&gt;3. &lt;b&gt;신경 연결 지도 (Connectome)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;661&quot; data-start=&quot;485&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;661&quot; data-start=&quot;485&quot;&gt;예쁜꼬마선충은 세계 최초로 **신경 연결 지도(Connectome)**가 완전히 밝혀진 생물입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;661&quot; data-start=&quot;545&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;606&quot; data-start=&quot;545&quot;&gt;신경세포 간의 모든 연결 관계가 1986년 연구(시드니 브레너와 동료들)에 의해 완전하게 지도화되었습니다.&lt;/li&gt;
&lt;li data-end=&quot;661&quot; data-start=&quot;609&quot;&gt;이 신경 지도는 학습, 기억, 운동 조절, 감각 입력 등에 대한 연구에 중요한 자료입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;680&quot; data-start=&quot;663&quot; data-ke-size=&quot;size23&quot;&gt;4. &lt;b&gt;기능적 특성&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;844&quot; data-start=&quot;681&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;735&quot; data-start=&quot;681&quot;&gt;&lt;b&gt;감각 신경&lt;/b&gt;: 빛, 화학 물질, 온도, 압력 등을 감지하는 감각신경이 발달되어 있습니다.&lt;/li&gt;
&lt;li data-end=&quot;780&quot; data-start=&quot;736&quot;&gt;&lt;b&gt;운동 신경&lt;/b&gt;: 95개의 근육 세포를 제어하여 몸의 움직임을 조정합니다.&lt;/li&gt;
&lt;li data-end=&quot;844&quot; data-start=&quot;781&quot;&gt;&lt;b&gt;인터뉴런(Interneuron)&lt;/b&gt;: 감각과 운동 신경 간의 신호를 조정하며 복잡한 신경회로를 형성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;865&quot; data-start=&quot;846&quot; data-ke-size=&quot;size23&quot;&gt;5. &lt;b&gt;연구에서의 활용&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1036&quot; data-start=&quot;866&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;921&quot; data-start=&quot;866&quot;&gt;&lt;b&gt;학습과 기억 연구&lt;/b&gt;: 단순한 학습 반응(고전적 조건화, 감각 적응)을 관찰할 수 있습니다.&lt;/li&gt;
&lt;li data-end=&quot;990&quot; data-start=&quot;922&quot;&gt;&lt;b&gt;유전자와 신경 기능의 연관성&lt;/b&gt;: 유전자 조작이 용이하여 특정 유전자가 신경계에 미치는 영향을 연구할 수 있습니다.&lt;/li&gt;
&lt;li data-end=&quot;1036&quot; data-start=&quot;991&quot;&gt;&lt;b&gt;약물 테스트&lt;/b&gt;: 신경계에 작용하는 약물의 효과를 관찰하는 데 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1105&quot; data-start=&quot;1038&quot; data-ke-size=&quot;size16&quot;&gt;예쁜꼬마선충의 신경계는 단순하면서도 매우 체계적이어서 복잡한 생물의 신경 시스템을 이해하기 위한 모델로 널리 사용됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;프로그램 코드&lt;/blockquote&gt;
&lt;pre id=&quot;code_1740468354511&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

public class NeuralConnectome {

    // 클래스: 신경 세포를 나타내는 노드
    static class Neuron {
        String name;

        Neuron(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    // 그래프 구조: 신경 세포와 연결을 저장
    static class NeuralGraph {
        private Map&amp;lt;Neuron, List&amp;lt;Neuron&amp;gt;&amp;gt; connections;

        NeuralGraph() {
            connections = new HashMap&amp;lt;&amp;gt;();
        }

        // 신경 세포 추가
        public void addNeuron(String name) {
            Neuron neuron = new Neuron(name);
            connections.putIfAbsent(neuron, new ArrayList&amp;lt;&amp;gt;());
        }

        // 연결 추가
        public void addConnection(String from, String to) {
            Neuron fromNeuron = findNeuron(from);
            Neuron toNeuron = findNeuron(to);

            if (fromNeuron != null &amp;amp;&amp;amp; toNeuron != null) {
                connections.get(fromNeuron).add(toNeuron);
            }
        }

        // 특정 신경 세포 찾기
        private Neuron findNeuron(String name) {
            for (Neuron neuron : connections.keySet()) {
                if (neuron.name.equals(name)) {
                    return neuron;
                }
            }
            return null;
        }

        // 특정 신경 세포의 연결 출력
        public void printConnections(String name) {
            Neuron neuron = findNeuron(name);
            if (neuron != null) {
                System.out.println(&quot;Connections for &quot; + neuron.name + &quot;: &quot; + connections.get(neuron));
            } else {
                System.out.println(&quot;Neuron &quot; + name + &quot; not found.&quot;);
            }
        }

        // 그래프 전체 출력
        public void printGraph() {
            for (Map.Entry&amp;lt;Neuron, List&amp;lt;Neuron&amp;gt;&amp;gt; entry : connections.entrySet()) {
                System.out.println(entry.getKey() + &quot; -&amp;gt; &quot; + entry.getValue());
            }
        }
    }

    public static void main(String[] args) {
        NeuralGraph connectome = new NeuralGraph();

        // 예쁜꼬마선충 신경 세포 추가 (예시 데이터)
        connectome.addNeuron(&quot;A&quot;);
        connectome.addNeuron(&quot;B&quot;);
        connectome.addNeuron(&quot;C&quot;);
        connectome.addNeuron(&quot;D&quot;);

        // 신경 연결 추가 (예시 데이터)
        connectome.addConnection(&quot;A&quot;, &quot;B&quot;);
        connectome.addConnection(&quot;A&quot;, &quot;C&quot;);
        connectome.addConnection(&quot;B&quot;, &quot;D&quot;);
        connectome.addConnection(&quot;C&quot;, &quot;D&quot;);

        // 그래프 출력
        System.out.println(&quot;Complete Neural Connectome:&quot;);
        connectome.printGraph();

        // 특정 신경 세포의 연결 출력
        System.out.println(&quot;\nConnections for a specific neuron:&quot;);
        connectome.printConnections(&quot;A&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;프로그램 설명&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2935&quot; data-start=&quot;2889&quot;&gt;&lt;b&gt;Neuron 클래스&lt;/b&gt;: 신경 세포를 나타냅니다. 이름으로 구별합니다.&lt;/li&gt;
&lt;li data-end=&quot;3128&quot; data-start=&quot;2936&quot;&gt;&lt;b&gt;NeuralGraph 클래스&lt;/b&gt;: 그래프 구조로 신경 연결을 관리합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3128&quot; data-start=&quot;2988&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3012&quot; data-start=&quot;2988&quot;&gt;addNeuron: 신경 세포 추가.&lt;/li&gt;
&lt;li data-end=&quot;3050&quot; data-start=&quot;3016&quot;&gt;addConnection: 신경 세포 간의 연결 추가.&lt;/li&gt;
&lt;li data-end=&quot;3092&quot; data-start=&quot;3054&quot;&gt;printConnections: 특정 신경 세포의 연결 출력.&lt;/li&gt;
&lt;li data-end=&quot;3128&quot; data-start=&quot;3096&quot;&gt;printGraph: 전체 신경 연결 그래프 출력.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;3173&quot; data-start=&quot;3129&quot;&gt;&lt;b&gt;main 메서드&lt;/b&gt;: 신경 세포와 연결 정보를 입력하고 출력합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;실행 결과 (예시)&lt;/blockquote&gt;
&lt;pre id=&quot;code_1740468514941&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Complete Neural Connectome:
A -&amp;gt; [B, C]
B -&amp;gt; [D]
C -&amp;gt; [D]
D -&amp;gt; []

Connections for a specific neuron:
Connections for A: [B, C]&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;확장 가능성&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3411&quot; data-start=&quot;3338&quot;&gt;실제 C. elegans의 신경 연결 데이터를 가져와서 프로그램에 통합할 수 있습니다. (CSV 파일이나 데이터베이스에서 로드)&lt;/li&gt;
&lt;li data-end=&quot;3455&quot; data-start=&quot;3412&quot;&gt;연결 강도(가중치)를 추가하여 신호 전달 시뮬레이션을 수행할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그램/Java</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/3</guid>
      <comments>https://neorc.tistory.com/3#entry3comment</comments>
      <pubDate>Tue, 25 Feb 2025 16:29:55 +0900</pubDate>
    </item>
    <item>
      <title>뇌 구조 정보가 정리된 동물</title>
      <link>https://neorc.tistory.com/2</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;뇌&amp;nbsp;구조&amp;nbsp;정보가&amp;nbsp;정리된&amp;nbsp;동물은&amp;nbsp;주로&amp;nbsp;과학&amp;nbsp;연구에서&amp;nbsp;많이&amp;nbsp;다뤄진&amp;nbsp;동물들입니다.&amp;nbsp;&lt;br /&gt;특히, 다음과 같은 동물들이 뇌 구조와 기능에 대해 잘 연구되어 있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인간&amp;nbsp;(Homo&amp;nbsp;sapiens)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;인간 뇌는 가장 정교하게 연구된 뇌입니다. 특히 해마, 대뇌 피질, 시상 등 다양한 영역의 구조와 기능이 상세히 밝혀져 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;쥐&amp;nbsp;(Rats)와&amp;nbsp;생쥐&amp;nbsp;(Mice)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;실험&amp;nbsp;동물로&amp;nbsp;널리&amp;nbsp;사용되며,&amp;nbsp;유전자&amp;nbsp;조작이&amp;nbsp;용이해&amp;nbsp;뇌&amp;nbsp;구조와&amp;nbsp;관련된&amp;nbsp;연구가&amp;nbsp;많이&amp;nbsp;이루어졌습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;초파리&amp;nbsp;(Drosophila&amp;nbsp;melanogaster)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;신경회로&amp;nbsp;연구에&amp;nbsp;적합하며,&amp;nbsp;간단한&amp;nbsp;뇌&amp;nbsp;구조를&amp;nbsp;가지고&amp;nbsp;있어&amp;nbsp;유전자와&amp;nbsp;뇌&amp;nbsp;기능의&amp;nbsp;관계를&amp;nbsp;연구하는&amp;nbsp;데&amp;nbsp;활용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;예쁜꼬마선충&amp;nbsp;(C.&amp;nbsp;elegans)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;신경계가&amp;nbsp;단순하고&amp;nbsp;신경&amp;nbsp;세포&amp;nbsp;302개가&amp;nbsp;모두&amp;nbsp;정리되어&amp;nbsp;있어&amp;nbsp;신경회로&amp;nbsp;지도화가&amp;nbsp;완료된&amp;nbsp;동물입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;원숭이&amp;nbsp;(Primates,&amp;nbsp;특히&amp;nbsp;Rhesus&amp;nbsp;monkeys)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;인간과&amp;nbsp;유사한&amp;nbsp;뇌&amp;nbsp;구조를&amp;nbsp;가지고&amp;nbsp;있어&amp;nbsp;고등&amp;nbsp;신경&amp;nbsp;활동&amp;nbsp;연구에&amp;nbsp;사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;물고기&amp;nbsp;(특히&amp;nbsp;Zebrafish)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;투명한&amp;nbsp;유충&amp;nbsp;단계에서&amp;nbsp;뇌를&amp;nbsp;실시간으로&amp;nbsp;관찰할&amp;nbsp;수&amp;nbsp;있어&amp;nbsp;신경&amp;nbsp;발달&amp;nbsp;연구에&amp;nbsp;적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;문어&amp;nbsp;(Octopus)&amp;nbsp;및&amp;nbsp;오징어
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;무척추동물&amp;nbsp;중에서&amp;nbsp;가장&amp;nbsp;복잡한&amp;nbsp;뇌를&amp;nbsp;가지고&amp;nbsp;있어&amp;nbsp;학습과&amp;nbsp;기억&amp;nbsp;연구에&amp;nbsp;사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위&amp;nbsp;동물들은&amp;nbsp;각기&amp;nbsp;다른&amp;nbsp;연구&amp;nbsp;목적에&amp;nbsp;따라&amp;nbsp;선택되며,&amp;nbsp;특히&amp;nbsp;신경과학에서&amp;nbsp;중요한&amp;nbsp;데이터를&amp;nbsp;제공합니다.&lt;/p&gt;</description>
      <category>과학/뇌구조</category>
      <category>뇌 과학</category>
      <category>뇌 구조</category>
      <category>뇌 구조 동물</category>
      <category>뇌 동물</category>
      <category>뇌 정보</category>
      <category>예쁜꼬마선충</category>
      <category>초파리</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/2</guid>
      <comments>https://neorc.tistory.com/2#entry2comment</comments>
      <pubDate>Tue, 25 Feb 2025 16:20:43 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 복사 대상 파일의 최상위 폴더 구조 포함하여 복사</title>
      <link>https://neorc.tistory.com/1</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;특정 폴더에 복사 대상 파일의 최상의 폴더구조까지 복사하기&lt;/span&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;br&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;br&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;&lt;li&gt;대상 파일의 최상의 폴더구조를 확인하여 저장&lt;/li&gt;&lt;li&gt;복사 하고자 하는 폴더에 대상 파일의 폴더구조를 생성&lt;/li&gt;&lt;li&gt;대상파일을 특정 폴더에 복사&lt;/li&gt;&lt;/ol&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class FileCopy {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void copyFile(String sourcePath, String destinationPath) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File sourceFile = new File(sourcePath);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File destinationFile = new File(destinationPath);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 원본 파일의 최상위 폴더 경로 구조 복사
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String sourceCanonicalPath = sourceFile.getCanonicalPath();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String destinationCanonicalPath = destinationFile.getCanonicalPath();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String relativePath = sourceCanonicalPath.substring(0, sourceCanonicalPath.lastIndexOf(File.separator));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File sourceParent = new File(relativePath);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File destinationParent = new File(destinationCanonicalPath).getParentFile();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;createParentDirectoriesInOrder(sourceParent, destinationParent);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch (IOException e) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.err.println(&quot;폴더 구조 생성 중 오류 발생: &quot; + e.getMessage());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FileInputStream fis = new FileInputStream(sourceFile);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // 복사시 파일경로를 상이하다면 createParentDirectoriesInOrder 에서 최종경로 리턴으로 변경하여 사용
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FileOutputStream fos = new FileOutputStream(destinationFile)) {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;byte[] buffer = new byte[1024];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int bytesRead;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while ((bytesRead = fis.read(buffer)) != -1) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fos.write(buffer, 0, bytesRead);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;파일 복사가 완료되었습니다: &quot; + destinationPath);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch (IOException e) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.err.println(&quot;파일 복사 중 오류 발생: &quot; + e.getMessage());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 원본 폴더 구조를 최상위부터 순서대로 복사할 위치에 재현
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void createParentDirectoriesInOrder(File sourceParent, File destinationParent) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;List&amp;lt;File&amp;gt; parentFolders = new ArrayList&amp;lt;&amp;gt;();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File currentSource = sourceParent;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 상위 폴더들을 리스트에 저장 (최상위부터)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (currentSource != null) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parentFolders.add(0, currentSource);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;currentSource = currentSource.getParentFile();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 저장된 리스트 순서대로 폴더 생성
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File currentDestination = destinationParent;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (File folder : parentFolders) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File newDir = new File(currentDestination, folder.getName());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (!newDir.exists()) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (newDir.mkdir()) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;폴더 생성: &quot; + newDir.getAbsolutePath());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} else {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.err.println(&quot;폴더 생성 실패: &quot; + newDir.getAbsolutePath());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;currentDestination = newDir;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch (Exception e) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.err.println(&quot;폴더 구조 복사 중 오류 발생: &quot; + e.getMessage());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void printFolderInfo(String filePath) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File file = new File(filePath);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;파일 경로: &quot; + file.getAbsolutePath());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;부모 폴더: &quot; + file.getParent());

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File parent = file.getParentFile();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;상위 폴더 경로:&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (parent != null) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;- &quot; + parent.getAbsolutePath());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parent = parent.getParentFile();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (args.length &amp;lt; 2) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;사용법: java FileCopy &amp;lt;원본 파일 경로&amp;gt; &amp;lt;복사할 파일 경로&amp;gt;&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;copyFile(args[0], args[1]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printFolderInfo(args[0]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그램/Java</category>
      <category>부모폴더복사</category>
      <category>자바</category>
      <category>최상위 폴더</category>
      <category>파일복사</category>
      <category>폴더복사</category>
      <category>폴더정보</category>
      <category>하위 폴더</category>
      <author>neorc</author>
      <guid isPermaLink="true">https://neorc.tistory.com/1</guid>
      <comments>https://neorc.tistory.com/1#entry1comment</comments>
      <pubDate>Tue, 25 Feb 2025 16:07:14 +0900</pubDate>
    </item>
  </channel>
</rss>