<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자는어디까지공부해야할까?</title>
    <link>https://djlife.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 8 Aug 2026 05:18:59 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor></managingEditor>
    <image>
      <title>개발자는어디까지공부해야할까?</title>
      <url>https://tistory1.daumcdn.net/tistory/5860502/attach/31a14de28f98493d96e9a8a604a2402f</url>
      <link>https://djlife.tistory.com</link>
    </image>
    <item>
      <title>AWS Summit 2026 후기 - 여기어때 Oracle &amp;rarr; Aurora MySQL 마이그레이션 세션</title>
      <link>https://djlife.tistory.com/55</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260520_171155494.jpg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPdM0S/dJMcagyPIBc/Ew4HMi5deae5HOfj49PuOk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPdM0S/dJMcagyPIBc/Ew4HMi5deae5HOfj49PuOk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPdM0S/dJMcagyPIBc/Ew4HMi5deae5HOfj49PuOk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPdM0S%2FdJMcagyPIBc%2FEw4HMi5deae5HOfj49PuOk%2Fimg.jpg&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;3000&quot; height=&quot;4000&quot; data-filename=&quot;KakaoTalk_20260520_171155494.jpg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;133&quot; data-start=&quot;55&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;133&quot; data-start=&quot;55&quot; data-ke-size=&quot;size16&quot;&gt;이번 AWS Summit에서 가장 인상 깊게 들었던 세션 중 하나는 여기어때의 Oracle &amp;rarr; Aurora MySQL 마이그레이션 사례였다.&lt;/p&gt;
&lt;p data-end=&quot;249&quot; data-start=&quot;135&quot; data-ke-size=&quot;size16&quot;&gt;현재 나도 사내 시스템에서 Stored Procedure 기반 구조를 JPA 기반 구조로 점진적으로 전환하는 작업을 진행하고 있어서 그런지 단순 사례 발표보다는 실제 현업 관점에서 공감되는 부분이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;356&quot; data-start=&quot;296&quot; data-ke-size=&quot;size16&quot;&gt;발표를 들으면서 가장 크게 느낀 건 생각보다 &lt;b&gt;변환&lt;/b&gt; 자체는 더 이상 가장 어려운 영역이 아니라는 점이었다.&lt;/p&gt;
&lt;p data-end=&quot;489&quot; data-start=&quot;358&quot; data-ke-size=&quot;size16&quot;&gt;예전에는 Oracle SP를 사람이 직접 해석하고 MyBatis나 JPA 코드로 하나씩 옮기는 작업 자체가 큰 비용이었다면,&lt;/p&gt;
&lt;p data-end=&quot;489&quot; data-start=&quot;358&quot; data-ke-size=&quot;size16&quot;&gt;지금은 Claude나 Amazon Q 같은 생성형 AI를 활용하면 기본적인 변환 속도 자체는 상당히 빨라졌다.&lt;/p&gt;
&lt;p data-end=&quot;489&quot; data-start=&quot;358&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;538&quot; data-start=&quot;491&quot; data-ke-size=&quot;size16&quot;&gt;실제로 반복적인 패턴이나 단순 CRUD 성격의 로직들은 꽤 높은 수준으로 변환해준다.&lt;/p&gt;
&lt;p data-end=&quot;607&quot; data-start=&quot;540&quot; data-ke-size=&quot;size16&quot;&gt;하지만 직접 SP &amp;rarr; JPA 전환 작업을 진행하면서 느끼는 건 결국 어려운 건 코드 작성이 아니라 &lt;b&gt;검증&lt;/b&gt;이라는 점이다.&lt;/p&gt;
&lt;p data-end=&quot;607&quot; data-start=&quot;540&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;686&quot; data-start=&quot;609&quot; data-ke-size=&quot;size16&quot;&gt;특히 레거시 Stored Procedure는 단순 SQL 집합이라기보다 운영 과정에서 누적된 비즈니스 정책 그 자체에 가까운 경우가 많다.&lt;/p&gt;
&lt;p data-end=&quot;755&quot; data-start=&quot;688&quot; data-ke-size=&quot;size16&quot;&gt;코드만 보면 왜 이렇게 작성되어 있는지 이해되지 않는 부분들도 실제 운영 데이터와 함께 보면 이유가 보이는 경우가 많다.&lt;/p&gt;
&lt;p data-end=&quot;755&quot; data-start=&quot;688&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;763&quot; data-start=&quot;757&quot; data-ke-size=&quot;size16&quot;&gt;예를 들자면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;835&quot; data-start=&quot;764&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;786&quot; data-start=&quot;764&quot; data-section-id=&quot;12vurr6&quot;&gt;특정 상태값을 중복으로 체크하는 로직&lt;/li&gt;
&lt;li data-end=&quot;806&quot; data-start=&quot;787&quot; data-section-id=&quot;xlcood&quot;&gt;순서가 비효율적으로 보이는 처리&lt;/li&gt;
&lt;li data-end=&quot;818&quot; data-start=&quot;807&quot; data-section-id=&quot;1lzylho&quot;&gt;오래된 예외 분기&lt;/li&gt;
&lt;li data-end=&quot;835&quot; data-start=&quot;819&quot; data-section-id=&quot;1afoyku&quot;&gt;의미를 알 수 없는 조건문&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;896&quot; data-start=&quot;837&quot; data-ke-size=&quot;size16&quot;&gt;같은 부분들도 실제로는 장애 대응이나 운영 중 발생했던 특정 케이스들을 처리하기 위해 유지된 경우가 많다.&lt;/p&gt;
&lt;p data-end=&quot;926&quot; data-start=&quot;898&quot; data-ke-size=&quot;size16&quot;&gt;이런 부분은 결국 정적 분석만으로는 파악이 어렵다.&lt;/p&gt;
&lt;p data-end=&quot;926&quot; data-start=&quot;898&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;934&quot; data-start=&quot;928&quot; data-ke-size=&quot;size16&quot;&gt;AI 전환 시&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;965&quot; data-start=&quot;935&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;946&quot; data-start=&quot;935&quot; data-section-id=&quot;xn66b&quot;&gt;SQL 구조 분석&lt;/li&gt;
&lt;li data-end=&quot;954&quot; data-start=&quot;947&quot; data-section-id=&quot;h4jkkd&quot;&gt;문법 변환&lt;/li&gt;
&lt;li data-end=&quot;965&quot; data-start=&quot;955&quot; data-section-id=&quot;hljpd9&quot;&gt;반복 패턴 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1024&quot; data-start=&quot;967&quot; data-ke-size=&quot;size16&quot;&gt;에는 강점을 보이지만, 운영 환경에서 누적된 데이터 흐름과 비즈니스 맥락까지 완전히 이해하지는 못한다.&lt;/p&gt;
&lt;p data-end=&quot;1069&quot; data-start=&quot;1026&quot; data-ke-size=&quot;size16&quot;&gt;그래서 결국 마지막 검증 책임은 개발자가 가져갈 수밖에 없다는 생각이 들었다.&lt;/p&gt;
&lt;p data-end=&quot;1069&quot; data-start=&quot;1026&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1113&quot; data-start=&quot;1071&quot; data-ke-size=&quot;size16&quot;&gt;현재 일부 로직들은 Shadow Test 형태로 비교 검증을 진행하고 있다.&lt;/p&gt;
&lt;p data-end=&quot;1113&quot; data-start=&quot;1071&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1136&quot; data-start=&quot;1115&quot; data-ke-size=&quot;size16&quot;&gt;조회성 로직은 비교적 접근이 단순하다.&lt;/p&gt;
&lt;p data-end=&quot;1202&quot; data-start=&quot;1138&quot; data-ke-size=&quot;size16&quot;&gt;기존 SP 결과와 신규 JPA 결과를 동일 조건으로 조회한 뒤 결과를 비교하면 어느 정도 검증이 가능하기 때문이다.&lt;/p&gt;
&lt;p data-end=&quot;1254&quot; data-start=&quot;1204&quot; data-ke-size=&quot;size16&quot;&gt;하지만 실제로 어려운 영역은 CUD(Create / Update / Delete) 쪽이다.&lt;/p&gt;
&lt;p data-end=&quot;1254&quot; data-start=&quot;1204&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1292&quot; data-start=&quot;1256&quot; data-ke-size=&quot;size16&quot;&gt;특히 UPDATE 계열 로직들은 단순 데이터 수정 수준이 아니라:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1343&quot; data-start=&quot;1293&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1307&quot; data-start=&quot;1293&quot; data-section-id=&quot;iwvf4g&quot;&gt;여러 테이블 동시 갱신&lt;/li&gt;
&lt;li data-end=&quot;1315&quot; data-start=&quot;1308&quot; data-section-id=&quot;m50b1k&quot;&gt;상태 변경&lt;/li&gt;
&lt;li data-end=&quot;1323&quot; data-start=&quot;1316&quot; data-section-id=&quot;1v7n8wp&quot;&gt;누적 계산&lt;/li&gt;
&lt;li data-end=&quot;1329&quot; data-start=&quot;1324&quot; data-section-id=&quot;2h9bvc&quot;&gt;후처리&lt;/li&gt;
&lt;li data-end=&quot;1343&quot; data-start=&quot;1330&quot; data-section-id=&quot;1gktntk&quot;&gt;커서 기반 순차 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1376&quot; data-start=&quot;1345&quot; data-ke-size=&quot;size16&quot;&gt;등이 하나의 트랜잭션 안에서 함께 수행되는 경우가 많다.&lt;/p&gt;
&lt;p data-end=&quot;1437&quot; data-start=&quot;1378&quot; data-ke-size=&quot;size16&quot;&gt;문제는 이런 로직들을 코드 레벨에서 Shadow Test 방식으로 검증하기가 생각보다 쉽지 않다는 점이다.&lt;/p&gt;
&lt;p data-end=&quot;1437&quot; data-start=&quot;1378&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1522&quot; data-start=&quot;1439&quot; data-ke-size=&quot;size16&quot;&gt;인프라 레벨 Shadow Traffic처럼 요청 자체를 복제하는 구조와는 다르게 지금 진행 중인 작업은 코드 자체를 교체하는 작업에 가깝기 때문이다.&lt;/p&gt;
&lt;p data-end=&quot;1522&quot; data-start=&quot;1439&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1532&quot; data-start=&quot;1524&quot; data-ke-size=&quot;size16&quot;&gt;현 시점은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1593&quot; data-start=&quot;1533&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1543&quot; data-start=&quot;1533&quot; data-section-id=&quot;1dyt741&quot;&gt;롤백 기반 비교&lt;/li&gt;
&lt;li data-end=&quot;1560&quot; data-start=&quot;1544&quot; data-section-id=&quot;1xpcpgg&quot;&gt;특정 키 기준 정합성 검증&lt;/li&gt;
&lt;li data-end=&quot;1579&quot; data-start=&quot;1561&quot; data-section-id=&quot;82rezk&quot;&gt;SP 결과와 JPA 결과 대조&lt;/li&gt;
&lt;li data-end=&quot;1593&quot; data-start=&quot;1580&quot; data-section-id=&quot;nvlkik&quot;&gt;케이스별 데이터 비교&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1626&quot; data-start=&quot;1595&quot; data-ke-size=&quot;size16&quot;&gt;같은 방식들을 계속 고민하며 검증 범위를 넓혀가고 있다.&lt;/p&gt;
&lt;p data-end=&quot;1646&quot; data-start=&quot;1628&quot; data-ke-size=&quot;size16&quot;&gt;최근 가장 크게 느끼는 건 결국:&lt;/p&gt;
&lt;blockquote data-end=&quot;1698&quot; data-start=&quot;1648&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1698&quot; data-start=&quot;1650&quot; data-ke-size=&quot;size16&quot;&gt;동작한다와&lt;br /&gt;운영 가능한 수준으로 안전하다는 완전히 다른 문제라는 점이다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;1731&quot; data-start=&quot;1700&quot; data-ke-size=&quot;size16&quot;&gt;로컬 환경에서는 정상 동작하더라도 실제 운영 환경에서는...&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1771&quot; data-start=&quot;1732&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1741&quot; data-start=&quot;1732&quot; data-section-id=&quot;1yils0h&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;데이터 정합성&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1747&quot; data-start=&quot;1742&quot; data-section-id=&quot;20gmak&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;동시성&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1754&quot; data-start=&quot;1748&quot; data-section-id=&quot;1j3uixv&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Lock&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1762&quot; data-start=&quot;1755&quot; data-section-id=&quot;ur1dcp&quot;&gt;순서 보장&lt;/li&gt;
&lt;li data-end=&quot;1771&quot; data-start=&quot;1763&quot; data-section-id=&quot;b79pm5&quot;&gt;타이밍 이슈&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1789&quot; data-start=&quot;1773&quot; data-ke-size=&quot;size16&quot;&gt;같은 문제들이 계속 발생한다.&lt;/p&gt;
&lt;p data-end=&quot;1903&quot; data-start=&quot;1791&quot; data-ke-size=&quot;size16&quot;&gt;특히 몇 년 이상 운영된 Stored Procedure들은 이미 수많은 장애와 예외 상황을 거치며 높은 확률로 안정화된 코드들이기 때문에&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1903&quot; data-start=&quot;1791&quot; data-ke-size=&quot;size16&quot;&gt;단순히 JPA로 다시 작성하는 것만으로는 해결되지 않는 경우가 많다.&lt;/p&gt;
&lt;p data-end=&quot;1966&quot; data-start=&quot;1905&quot; data-ke-size=&quot;size16&quot;&gt;요즘은 이 작업이 단순 리팩토링이라기보다 운영 중인 비즈니스 로직을 재현하는 작업에 더 가깝다는 생각이 든다.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;2064&quot; data-start=&quot;1968&quot; data-ke-size=&quot;size16&quot;&gt;이번 세션도 단순히 Oracle DB 에서 Aurora Mysql DB로 이전했다는 성공 사례보다는 실제 운영 환경에서 어떤 방식으로 검증하고 안정성을 확보했는지에 대한 이야기가 많아서 더 인상 깊게 남았다.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;2064&quot; data-start=&quot;1968&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;2064&quot; data-start=&quot;1968&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ref.&lt;/b&gt;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;2064&quot; data-start=&quot;1968&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/blogs/tech/oracle-to-amazon-aurora-mysql-migration-journey/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://aws.amazon.com/ko/blogs/tech/oracle-to-amazon-aurora-mysql-migration-journey/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1779523371930&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Oracle에서 Amazon Aurora MySQL로: 여기어때의 6주간 데이터베이스 마이그레이션 여정 | Amazon Web Services&quot; data-og-description=&quot;개요 여기어때컴퍼니는 대한민국 대표 여행 플랫폼 기업으로 운영하며 숙박&amp;middot;항공&amp;middot;레저까지 통합 여행 서비스를 제공하고 있습니다. 2025년 1월, 여기어때컴퍼니는 온라인투어를 인수하면서 항&quot; data-og-host=&quot;aws.amazon.com&quot; data-og-source-url=&quot;https://aws.amazon.com/ko/blogs/tech/oracle-to-amazon-aurora-mysql-migration-journey/&quot; data-og-url=&quot;https://aws.amazon.com/ko/blogs/tech/oracle-to-amazon-aurora-mysql-migration-journey/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bdrlJV/dJMb8U8ZIz1/FB5qRmRnUFM0axQHRu15d1/img.png?width=1121&amp;amp;height=630&amp;amp;face=0_0_1121_630,https://scrap.kakaocdn.net/dn/bS6Hjk/dJMb9c9DTXx/1xzV92qpuwxiwYRyYf8Z60/img.png?width=1121&amp;amp;height=630&amp;amp;face=0_0_1121_630,https://scrap.kakaocdn.net/dn/bud1Do/dJMb8QMh9Aw/QEvm7dmTj8PPrNtx9PU0HK/img.jpg?width=1475&amp;amp;height=2213&amp;amp;face=497_719_1105_1382&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/blogs/tech/oracle-to-amazon-aurora-mysql-migration-journey/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://aws.amazon.com/ko/blogs/tech/oracle-to-amazon-aurora-mysql-migration-journey/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bdrlJV/dJMb8U8ZIz1/FB5qRmRnUFM0axQHRu15d1/img.png?width=1121&amp;amp;height=630&amp;amp;face=0_0_1121_630,https://scrap.kakaocdn.net/dn/bS6Hjk/dJMb9c9DTXx/1xzV92qpuwxiwYRyYf8Z60/img.png?width=1121&amp;amp;height=630&amp;amp;face=0_0_1121_630,https://scrap.kakaocdn.net/dn/bud1Do/dJMb8QMh9Aw/QEvm7dmTj8PPrNtx9PU0HK/img.jpg?width=1475&amp;amp;height=2213&amp;amp;face=497_719_1105_1382');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Oracle에서 Amazon Aurora MySQL로: 여기어때의 6주간 데이터베이스 마이그레이션 여정 | Amazon Web Services&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요 여기어때컴퍼니는 대한민국 대표 여행 플랫폼 기업으로 운영하며 숙박&amp;middot;항공&amp;middot;레저까지 통합 여행 서비스를 제공하고 있습니다. 2025년 1월, 여기어때컴퍼니는 온라인투어를 인수하면서 항&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://aws.amazon.com/ko/events/summits/seoul/agenda/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://aws.amazon.com/ko/events/summits/seoul/agenda/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1779764667109&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;강연 목록 | AWS Summit Seoul 2026&quot; data-og-description=&quot;2026년 5월 20-21일 오전 8시 30분: 등록 시작 오전 9시 30분 - 오전 10시 40분: 기조연설 오전 11시 10분 - 오후 4시 50분: 브레이크아웃 세션 오전 10시 - 오후 5시 30분: 엑스포&quot; data-og-host=&quot;aws.amazon.com&quot; data-og-source-url=&quot;https://aws.amazon.com/ko/events/summits/seoul/agenda/&quot; data-og-url=&quot;https://aws.amazon.com/ko/events/summits/seoul/agenda/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/q4Xw9/dJMb8U8ZZvA/kXbnWGBq4uGz0bKeLYey70/img.png?width=1440&amp;amp;height=660&amp;amp;face=0_0_1440_660&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/events/summits/seoul/agenda/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://aws.amazon.com/ko/events/summits/seoul/agenda/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/q4Xw9/dJMb8U8ZZvA/kXbnWGBq4uGz0bKeLYey70/img.png?width=1440&amp;amp;height=660&amp;amp;face=0_0_1440_660');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;강연 목록 | AWS Summit Seoul 2026&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2026년 5월 20-21일 오전 8시 30분: 등록 시작 오전 9시 30분 - 오전 10시 40분: 기조연설 오전 11시 10분 - 오후 4시 50분: 브레이크아웃 세션 오전 10시 - 오후 5시 30분: 엑스포&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>변소</category>
      <category>2026</category>
      <category>AWS</category>
      <category>AWS Summit</category>
      <category>AWS 서밋</category>
      <category>마이그레이션</category>
      <category>세션</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/55</guid>
      <comments>https://djlife.tistory.com/55#entry55comment</comments>
      <pubDate>Sat, 23 May 2026 17:36:58 +0900</pubDate>
    </item>
    <item>
      <title>헬스장가기싫은날 루틴</title>
      <link>https://djlife.tistory.com/54</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;헬스장가기귀찮&lt;br /&gt;&lt;br /&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&gt;월&lt;/td&gt;
&lt;td&gt;가슴 + 삼두&lt;/td&gt;
&lt;td&gt;푸쉬업&lt;/td&gt;
&lt;td&gt;4 &amp;times; 최대&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;덤벨 바닥 프레스&lt;/td&gt;
&lt;td&gt;4 &amp;times; 15~20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;덤벨 플라이&lt;/td&gt;
&lt;td&gt;3 &amp;times; 15~20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;오버헤드 삼두&lt;/td&gt;
&lt;td&gt;3 &amp;times; 15~20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;의자 딥스&lt;/td&gt;
&lt;td&gt;3 &amp;times; 최대&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;화&lt;/td&gt;
&lt;td&gt;등 + 이두&lt;/td&gt;
&lt;td&gt;덤벨 원암 로우&lt;/td&gt;
&lt;td&gt;4 &amp;times; 15~20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;덤벨 데드리프트&lt;/td&gt;
&lt;td&gt;4 &amp;times; 15~20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;덤벨 컬&lt;/td&gt;
&lt;td&gt;4 &amp;times; 15~20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;해머 컬&lt;/td&gt;
&lt;td&gt;3 &amp;times; 15~20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;수&lt;/td&gt;
&lt;td&gt;어깨 + 하체&lt;/td&gt;
&lt;td&gt;덤벨 스쿼트&lt;/td&gt;
&lt;td&gt;4 &amp;times; 20~25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;런지&lt;/td&gt;
&lt;td&gt;3 &amp;times; 15 (각 다리)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;힙 쓰러스트&lt;/td&gt;
&lt;td&gt;3 &amp;times; 20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;숄더 프레스&lt;/td&gt;
&lt;td&gt;4 &amp;times; 15~20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;레터럴 레이즈&lt;/td&gt;
&lt;td&gt;4 &amp;times; 15~20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;벤트오버 레이즈&lt;/td&gt;
&lt;td&gt;3 &amp;times; 15~20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;목&lt;/td&gt;
&lt;td&gt;휴식&lt;/td&gt;
&lt;td&gt;가벼운 걷기 or 스트레칭&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;금&lt;/td&gt;
&lt;td&gt;가슴 + 삼두&lt;/td&gt;
&lt;td&gt;월요일 반복&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;토&lt;/td&gt;
&lt;td&gt;등 + 이두&lt;/td&gt;
&lt;td&gt;화요일 반복&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일&lt;/td&gt;
&lt;td&gt;휴식&lt;/td&gt;
&lt;td&gt;완전 휴식&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <category>변소</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/54</guid>
      <comments>https://djlife.tistory.com/54#entry54comment</comments>
      <pubDate>Wed, 6 May 2026 22:07:18 +0900</pubDate>
    </item>
    <item>
      <title>[SpringBoot] Spring Boot 4.0.0 나왔다!!</title>
      <link>https://djlife.tistory.com/53</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Do5I6/dJMcah3TqiA/kGArekVovqGTCggiKZzmK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Do5I6/dJMcah3TqiA/kGArekVovqGTCggiKZzmK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Do5I6/dJMcah3TqiA/kGArekVovqGTCggiKZzmK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDo5I6%2FdJMcah3TqiA%2FkGArekVovqGTCggiKZzmK0%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;1280&quot; height=&quot;800&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;298&quot; data-start=&quot;120&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;298&quot; data-start=&quot;120&quot; data-ke-size=&quot;size16&quot;&gt;스프링 팀에서 2025-11-20 기준으로 Spring Boot &lt;b&gt;4.0.0 정식 버전&lt;/b&gt;을 공개했다.&lt;/p&gt;
&lt;p data-end=&quot;298&quot; data-start=&quot;120&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이제 Maven Central에서 바로 가져다 쓸 수 있고,&lt;/p&gt;
&lt;p data-end=&quot;298&quot; data-start=&quot;120&quot; data-ke-size=&quot;size16&quot;&gt;스프링 부트도 &lt;b&gt;3.x 세대 &amp;rarr; 4.x 세대&lt;/b&gt;로 한 단계 올라간 느낌이다. &lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&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;/p&gt;
&lt;p data-end=&quot;360&quot; data-start=&quot;300&quot; data-ke-size=&quot;size16&quot;&gt;공식 블로그와 릴리즈 노트를 기준으로,&lt;br /&gt;&lt;b&gt;백엔드 개발자 입장에서 중요한 포인트만&lt;/b&gt; 골라서 정리해본다.&lt;/p&gt;
&lt;p data-end=&quot;360&quot; data-start=&quot;300&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;392&quot; data-start=&quot;367&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 뭐가 크게 바뀐걸까?&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;472&quot; data-start=&quot;394&quot; data-ke-size=&quot;size16&quot;&gt;공식 블로그 기준으로 4.0의 키워드는 대략 이렇게 정리할 수 있다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;677&quot; data-start=&quot;474&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;501&quot; data-start=&quot;474&quot;&gt;&lt;b&gt;Spring Framework 7 기반&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;535&quot; data-start=&quot;502&quot;&gt;&lt;b&gt;코드베이스 전체 모듈화 &amp;rarr; 더 작고 집중된 JAR&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;576&quot; data-start=&quot;536&quot;&gt;&lt;b&gt;JSpecify 기반의 널 안정성(null-safety) 향상&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;617&quot; data-start=&quot;577&quot;&gt;&lt;b&gt;Java 25 1급 지원 (최소 지원은 여전히 Java 17)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;677&quot; data-start=&quot;618&quot;&gt;&lt;b&gt;API Versioning, HTTP Service Clients 같은 REST 개발 기능 강화&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;739&quot; data-start=&quot;679&quot; data-ke-size=&quot;size16&quot;&gt;거기에 더해서 릴리즈 노트까지 보면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;891&quot; data-start=&quot;741&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;754&quot; data-start=&quot;741&quot;&gt;Gradle 9 지원&lt;/li&gt;
&lt;li data-end=&quot;777&quot; data-start=&quot;755&quot;&gt;OpenTelemetry 스타터 추가&lt;/li&gt;
&lt;li data-end=&quot;816&quot; data-start=&quot;778&quot;&gt;HTTP/테스트/Redis/MongoDB 쪽 품질&amp;middot;운영 기능 보강&lt;/li&gt;
&lt;li data-end=&quot;891&quot; data-start=&quot;817&quot;&gt;스프링 생태계 전체(Spring Security 7, Spring Data 2025.1, Spring Batch 6 등) 버전 업&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;915&quot; data-start=&quot;893&quot; data-ke-size=&quot;size16&quot;&gt;요 정도를 &amp;ldquo;큰 틀&amp;rdquo;로 잡고 보면 된다.&lt;/p&gt;
&lt;p data-end=&quot;915&quot; data-start=&quot;893&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;950&quot; data-start=&quot;922&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 코드/아키텍처 관점에서 눈에 띄는 변화들&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-end=&quot;995&quot; data-start=&quot;952&quot; data-ke-size=&quot;size20&quot;&gt;2-1. 모듈화된 Spring Boot &amp;ndash; 더 작고, 더 쪼개진 JAR&lt;/h4&gt;
&lt;p data-end=&quot;1065&quot; data-start=&quot;997&quot; data-ke-size=&quot;size16&quot;&gt;스프링 부트 코드베이스가 &lt;b&gt;완전히 모듈화&lt;/b&gt;됐다. &lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1124&quot; data-start=&quot;1067&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1096&quot; data-start=&quot;1067&quot;&gt;필요한 기능만 의존성으로 가져올 수 있게 쪼개졌고&lt;/li&gt;
&lt;li data-end=&quot;1124&quot; data-start=&quot;1097&quot;&gt;JAR 단위가 더 작고 focused 해졌다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1143&quot; data-start=&quot;1126&quot; data-ke-size=&quot;size16&quot;&gt;실질적으로 기대할 수 있는 건:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1246&quot; data-start=&quot;1145&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1169&quot; data-start=&quot;1145&quot;&gt;Docker 이미지 레이어가 더 깔끔해짐&lt;/li&gt;
&lt;li data-end=&quot;1194&quot; data-start=&quot;1170&quot;&gt;스타터/모듈 단위로 기능을 나누기 쉬워짐&lt;/li&gt;
&lt;li data-end=&quot;1246&quot; data-start=&quot;1195&quot;&gt;&amp;ldquo;이 기능만 쓰고 싶은데 의존성이 너무 많이 딸려온다&amp;rdquo; 같은 답답함이 조금 줄어들 가능성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1315&quot; data-start=&quot;1248&quot; data-ke-size=&quot;size16&quot;&gt;새 프로젝트를 Spring Boot 4로 시작한다면,&lt;br /&gt;초반부터 모듈 구성을 신경 쓰면 꽤 깔끔한 구조를 가져갈 수 있을 것 같다.&lt;/p&gt;
&lt;p data-end=&quot;915&quot; data-start=&quot;893&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;915&quot; data-start=&quot;893&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;1357&quot; data-start=&quot;1322&quot; data-ke-size=&quot;size20&quot;&gt;2-2. JSpecify 기반 Null-Safety 강화&lt;/h4&gt;
&lt;p data-end=&quot;1455&quot; data-start=&quot;1359&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot 4는 &lt;b&gt;JSpecify 기반으로 널 관련 어노테이션/메타데이터를 강화&lt;/b&gt;했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1553&quot; data-start=&quot;1457&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1512&quot; data-start=&quot;1457&quot;&gt;메서드 파라미터/리턴 타입에 대해 &amp;ldquo;null이 올 수 있는지/없는지&amp;rdquo;가 더 정확하게 힌트로 붙고&lt;/li&gt;
&lt;li data-end=&quot;1553&quot; data-start=&quot;1513&quot;&gt;IDE나 정적 분석 툴에서 널 관련 경고를 더 잘 잡아줄 수 있게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1650&quot; data-start=&quot;1555&quot; data-ke-size=&quot;size16&quot;&gt;자바가 코틀린처럼 완전한 null-safe 언어는 아니지만,&lt;br /&gt;Spring 쪽에서 메타데이터를 잘 뿌려주면 **&amp;ldquo;실수로 NPE 내는 코드&amp;rdquo;**는 확실히 줄어들 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;915&quot; data-start=&quot;893&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;915&quot; data-start=&quot;893&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;1697&quot; data-start=&quot;1657&quot; data-ke-size=&quot;size20&quot;&gt;2-3. Java 25 1급 지원 (Java 17은 그대로 지원)&lt;/h4&gt;
&lt;p data-end=&quot;1822&quot; data-start=&quot;1699&quot; data-ke-size=&quot;size16&quot;&gt;이번 버전에서 &lt;b&gt;Java 25를 1급 시민으로 공식 지원&lt;/b&gt;한다.&lt;br /&gt;그렇다고 &amp;ldquo;17은 버렸다&amp;rdquo;가 아니라, &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;Java 17 호환성은 유지&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1916&quot; data-start=&quot;1824&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1852&quot; data-start=&quot;1824&quot;&gt;기존 LTS 기반(17)으로 여유 있게 운영하든&lt;/li&gt;
&lt;li data-end=&quot;1887&quot; data-start=&quot;1853&quot;&gt;JDK 25의 새로운 기능과 최적화를 적극적으로 쓰고 싶든&lt;/li&gt;
&lt;li data-end=&quot;1916&quot; data-start=&quot;1888&quot;&gt;둘 다 선택지가 열려 있는 상태라고 보면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1927&quot; data-start=&quot;1918&quot; data-ke-size=&quot;size16&quot;&gt;실무 느낌으로는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2028&quot; data-start=&quot;1929&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1978&quot; data-start=&quot;1929&quot;&gt;&lt;b&gt;새 프로젝트&lt;/b&gt; &amp;rarr; 여건 되면 Java 21 또는 25 + Boot 4 조합 고려&lt;/li&gt;
&lt;li data-end=&quot;2028&quot; data-start=&quot;1979&quot;&gt;&lt;b&gt;기존 프로젝트&lt;/b&gt; &amp;rarr; 당장은 17 + Boot 3.x 유지 &amp;rarr; 점진적 마이그레이션&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;2089&quot; data-start=&quot;2035&quot; data-ke-size=&quot;size20&quot;&gt;2-4. HTTP Service Clients &amp;ndash; 인터페이스만 쓰면 HTTP 클라이언트 끝&lt;/h4&gt;
&lt;p data-end=&quot;2206&quot; data-start=&quot;2091&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot 4에서는 &lt;b&gt;HTTP Service Clients&lt;/b&gt; 에 대한 auto-config 및 프로퍼티 지원이 들어갔다.&lt;/p&gt;
&lt;p data-end=&quot;2218&quot; data-start=&quot;2208&quot; data-ke-size=&quot;size16&quot;&gt;감각적으로 말하면,&lt;/p&gt;
&lt;blockquote data-end=&quot;2247&quot; data-start=&quot;2220&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2247&quot; data-start=&quot;2222&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;Feign 느낌 + Spring 공식 버전&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;2262&quot; data-start=&quot;2249&quot; data-ke-size=&quot;size16&quot;&gt;이라고 생각하면 편하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2377&quot; data-start=&quot;2264&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2325&quot; data-start=&quot;2264&quot;&gt;@HttpExchange, @GetExchange, @PostExchange 같은 어노테이션으로&lt;/li&gt;
&lt;li data-end=&quot;2350&quot; data-start=&quot;2326&quot;&gt;&lt;b&gt;평범한 자바 인터페이스&lt;/b&gt;만 정의하면&lt;/li&gt;
&lt;li data-end=&quot;2377&quot; data-start=&quot;2351&quot;&gt;스프링이 알아서 구현체를 만들어 주는 방식.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2407&quot; data-start=&quot;2379&quot; data-ke-size=&quot;size16&quot;&gt;예를 들면 이런 느낌으로 쓸 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;2407&quot; data-start=&quot;2379&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1763704727400&quot; class=&quot;less&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;@HttpExchange(url = &quot;https://api.example.com&quot;)
public interface UserClient {

    @GetExchange(&quot;/users/{id}&quot;)
    UserResponse getUser(@PathVariable Long id);

    @PostExchange(&quot;/users&quot;)
    UserResponse createUser(@RequestBody CreateUserRequest req);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;2407&quot; data-start=&quot;2379&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2700&quot; data-start=&quot;2677&quot; data-ke-size=&quot;size16&quot;&gt;Boot에서 이걸 자동 구성해주기 때문에&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2772&quot; data-start=&quot;2702&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2743&quot; data-start=&quot;2702&quot;&gt;RestTemplate/WebClient로 매번 직접 호출로직 짜던 걸&lt;/li&gt;
&lt;li data-end=&quot;2772&quot; data-start=&quot;2744&quot;&gt;인터페이스 선언 + 주입만으로 정리할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;2819&quot; data-start=&quot;2779&quot; data-ke-size=&quot;size20&quot;&gt;2-5. API Versioning &amp;ndash; 부트에서 바로 버전링 지원&lt;/h4&gt;
&lt;p data-end=&quot;2932&quot; data-start=&quot;2821&quot; data-ke-size=&quot;size16&quot;&gt;Spring MVC / WebFlux 에서 API 버전 관리를 도와주는 &lt;b&gt;API Versioning 자동 설정&lt;/b&gt;이 추가됐다. &lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2993&quot; data-start=&quot;2934&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2961&quot; data-start=&quot;2934&quot;&gt;spring.mvc.apiversion.*&lt;/li&gt;
&lt;li data-end=&quot;2993&quot; data-start=&quot;2962&quot;&gt;spring.webflux.apiversion.*&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3159&quot; data-start=&quot;2995&quot; data-ke-size=&quot;size16&quot;&gt;같은 프로퍼티로 기본 전략을 지정할 수 있고,&lt;br /&gt;필요하면 ApiVersionResolver, ApiVersionParser, ApiVersionDeprecationHandler 같은 빈을 직접 정의해서&lt;br /&gt;버전 파싱/Deprecated 처리 정책을 세밀하게 커스터마이징할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;3192&quot; data-start=&quot;3161&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;URL에 v1, v2 붙이고 말지 뭐&amp;rdquo; 수준이 아니라:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3265&quot; data-start=&quot;3194&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3207&quot; data-start=&quot;3194&quot;&gt;헤더 기반 버전 관리&lt;/li&gt;
&lt;li data-end=&quot;3237&quot; data-start=&quot;3208&quot;&gt;Deprecated 버전 응답에 경고 헤더 붙이기&lt;/li&gt;
&lt;li data-end=&quot;3265&quot; data-start=&quot;3238&quot;&gt;특정 버전 이상에서만 허용되는 엔드포인트 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3305&quot; data-start=&quot;3267&quot; data-ke-size=&quot;size16&quot;&gt;프레임워크 스타일로 풀어줄 수 있는 기반이 생긴 셈이다.&lt;/p&gt;
&lt;p data-end=&quot;3305&quot; data-start=&quot;3267&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;3337&quot; data-start=&quot;3312&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 운영/테스트/관찰성 측면에서의 변화&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;3419&quot; data-start=&quot;3339&quot; data-ke-size=&quot;size16&quot;&gt;릴리즈 노트 쪽을 보면 운영/테스트 관련해서 꽤 눈에 띄는 것들이 있다. &lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-end=&quot;3441&quot; data-start=&quot;3421&quot; data-ke-size=&quot;size20&quot;&gt;3-1. Gradle 9 지원&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3506&quot; data-start=&quot;3443&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3478&quot; data-start=&quot;3443&quot;&gt;Spring Boot 4는 &lt;b&gt;Gradle 9 정식 지원&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;3506&quot; data-start=&quot;3479&quot;&gt;Gradle 8.x(8.14+)도 여전히 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3549&quot; data-start=&quot;3508&quot; data-ke-size=&quot;size16&quot;&gt;새 프로젝트 시작할 때 빌드 툴 버전을 조금 더 공격적으로 가져가도 된다.&lt;/p&gt;
&lt;h4 data-end=&quot;3585&quot; data-start=&quot;3556&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-end=&quot;3585&quot; data-start=&quot;3556&quot; data-ke-size=&quot;size20&quot;&gt;3-2. OpenTelemetry 스타터 추가&lt;/h4&gt;
&lt;p data-end=&quot;3677&quot; data-start=&quot;3587&quot; data-ke-size=&quot;size16&quot;&gt;새 스타터: spring-boot-starter-opentelemetry 가 추가됐다. &lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3753&quot; data-start=&quot;3679&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3721&quot; data-start=&quot;3679&quot;&gt;OTLP로 메트릭/트레이스 내보내는 데 필요한 의존성을 한 번에 가져오고&lt;/li&gt;
&lt;li data-end=&quot;3753&quot; data-start=&quot;3722&quot;&gt;OpenTelemetry SDK까지 자동 설정해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3812&quot; data-start=&quot;3755&quot; data-ke-size=&quot;size16&quot;&gt;즉, &amp;ldquo;관찰성&amp;rdquo; 쪽도 이제 부트 스타터 한 방으로 어느 정도 기본 셋업을 깔고 갈 수 있게 된 셈이다.&lt;/p&gt;
&lt;h4 data-end=&quot;3860&quot; data-start=&quot;3819&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-end=&quot;3860&quot; data-start=&quot;3819&quot; data-ke-size=&quot;size20&quot;&gt;3-3. RestTestClient &amp;ndash; 테스트용 HTTP 클라이언트&lt;/h4&gt;
&lt;p data-end=&quot;3944&quot; data-start=&quot;3862&quot; data-ke-size=&quot;size16&quot;&gt;테스트 쪽에는 RestTestClient라는 새로운 도구가 들어갔다. &lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4106&quot; data-start=&quot;3946&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4038&quot; data-start=&quot;3946&quot;&gt;@SpringBootTest + @AutoConfigureMockMvc 환경에서
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4038&quot; data-start=&quot;3999&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4038&quot; data-start=&quot;3999&quot;&gt;MockMvc 위에 얹은 RestTestClient를 주입해서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;4106&quot; data-start=&quot;4039&quot;&gt;실제 포트로 띄우는 통합 테스트에서도
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4106&quot; data-start=&quot;4064&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4106&quot; data-start=&quot;4064&quot;&gt;실행 중인 서버를 향하는 RestTestClient를 주입해서 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4177&quot; data-start=&quot;4108&quot; data-ke-size=&quot;size16&quot;&gt;MockMvc + WebTestClient 사이에서 고민하던 케이스들을&lt;br /&gt;조금 더 일관된 방식으로 가져갈 수 있을 듯하다.&lt;/p&gt;
&lt;p data-end=&quot;4177&quot; data-start=&quot;4108&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;4224&quot; data-start=&quot;4184&quot; data-ke-size=&quot;size20&quot;&gt;3-4. Redis, MongoDB, SSL Health 쪽 개선&lt;/h4&gt;
&lt;p data-end=&quot;4294&quot; data-start=&quot;4226&quot; data-ke-size=&quot;size16&quot;&gt;운영 관점에서 자주 쓰이는 기능들도 손을 봤다. &lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4531&quot; data-start=&quot;4296&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4343&quot; data-start=&quot;4296&quot;&gt;Redis Static Master/Replica 구성 auto-config 추가&lt;/li&gt;
&lt;li data-end=&quot;4416&quot; data-start=&quot;4344&quot;&gt;Redis 관찰성 개선 (MicrometerCommandLatencyRecorder &amp;rarr; MicrometerTracing 기반)&lt;/li&gt;
&lt;li data-end=&quot;4474&quot; data-start=&quot;4417&quot;&gt;MongoDB Health Indicator가 Spring Data MongoDB 없이도 동작 가능&lt;/li&gt;
&lt;li data-end=&quot;4531&quot; data-start=&quot;4475&quot;&gt;SSL Health/Info의 status 표현 방식 개선 (만료 임박 체인 정보 별도 노출 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4575&quot; data-start=&quot;4533&quot; data-ke-size=&quot;size16&quot;&gt;이런 것들은 전형적인 &amp;ldquo;운영하면서 계속 피드백 들어온 것들&amp;rdquo; 반영 느낌이다.&lt;/p&gt;
&lt;h4 data-end=&quot;4609&quot; data-start=&quot;4582&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-end=&quot;4609&quot; data-start=&quot;4582&quot; data-ke-size=&quot;size20&quot;&gt;3-5. Spring 생태계 전체 버전 업&lt;/h4&gt;
&lt;p data-end=&quot;4691&quot; data-start=&quot;4611&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot 4.0 기준으로 같이 올라간 스프링 프로젝트들&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4862&quot; data-start=&quot;4693&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4715&quot; data-start=&quot;4693&quot;&gt;Spring Framework 7.0&lt;/li&gt;
&lt;li data-end=&quot;4737&quot; data-start=&quot;4716&quot;&gt;Spring Security 7.0&lt;/li&gt;
&lt;li data-end=&quot;4758&quot; data-start=&quot;4738&quot;&gt;Spring Data 2025.1&lt;/li&gt;
&lt;li data-end=&quot;4777&quot; data-start=&quot;4759&quot;&gt;Spring Batch 6.0&lt;/li&gt;
&lt;li data-end=&quot;4794&quot; data-start=&quot;4778&quot;&gt;Reactor 2025.0&lt;/li&gt;
&lt;li data-end=&quot;4862&quot; data-start=&quot;4795&quot;&gt;그 외 AMQP, Kafka, GraphQL, REST Docs, Session 등 전반적인 메이저/마이너 업그레이드&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4870&quot; data-start=&quot;4864&quot; data-ke-size=&quot;size16&quot;&gt;결론적으로,&lt;/p&gt;
&lt;blockquote data-end=&quot;4925&quot; data-start=&quot;4872&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;4925&quot; data-start=&quot;4874&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;부트만 4.0으로 올리는 게 아니라,&lt;br /&gt;스프링 전체 세대를 한 번에 올리는 셈&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;4944&quot; data-start=&quot;4927&quot; data-ke-size=&quot;size16&quot;&gt;이라는 느낌으로 보는 게 맞다.&lt;/p&gt;
&lt;p data-end=&quot;4944&quot; data-start=&quot;4927&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;4985&quot; data-start=&quot;4951&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 마이그레이션 &amp;ndash; 기존 프로젝트들은 그러면 어떻게...?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;5088&quot; data-start=&quot;4987&quot; data-ke-size=&quot;size16&quot;&gt;릴리즈 노트 첫 문장부터 &lt;b&gt;&quot;업그레이드는 평소보다 좀 더 손이 갈 수 있다&quot;&lt;/b&gt; 고 못을 박고 시작한다. &lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;5095&quot; data-start=&quot;5090&quot; data-ke-size=&quot;size16&quot;&gt;정리하면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5236&quot; data-start=&quot;5097&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5159&quot; data-start=&quot;5097&quot;&gt;기존 &lt;b&gt;Spring Boot 3.5에서 4.0으로 가는 전용 Migration Guide&lt;/b&gt;가 따로 있다.&lt;/li&gt;
&lt;li data-end=&quot;5236&quot; data-start=&quot;5160&quot;&gt;3.5보다 더 낮은 버전(3.2, 3.1 등)을 쓰고 있다면
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5236&quot; data-start=&quot;5198&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5236&quot; data-start=&quot;5198&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;먼저 3.5까지 올린 다음에 4.0으로 가는 걸 추천&lt;/b&gt;&lt;/span&gt;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;5328&quot; data-start=&quot;5238&quot; data-ke-size=&quot;size16&quot;&gt;그리고 설정 변경들만 따로 모아놓은 &lt;b&gt;Configuration Changelog&lt;/b&gt; 도 있으니,&lt;br /&gt;yml/properties 손볼 때 필수로 같이 봐야 한다.&lt;/p&gt;
&lt;p data-end=&quot;5339&quot; data-start=&quot;5330&quot; data-ke-size=&quot;size16&quot;&gt;실무 감각으로는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5510&quot; data-start=&quot;5341&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5405&quot; data-start=&quot;5341&quot;&gt;새로 만드는 서비스&lt;br /&gt;&amp;rarr; 가능하면 Boot 4 + Spring Framework 7 기준으로 설계 시작&lt;/li&gt;
&lt;li data-end=&quot;5510&quot; data-start=&quot;5406&quot;&gt;이미 운영 중인 레거시 서비스&lt;br /&gt;&amp;rarr; &amp;ldquo;LTS + 회사 인프라 지원 범위 + 사용 중인 라이브러리 호환성&amp;rdquo; 을 보고&lt;br /&gt;순서를 정리해서 천천히 올리는 게 현실적일 것 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-end=&quot;5590&quot; data-start=&quot;5546&quot; data-ke-size=&quot;size16&quot;&gt;정리하면 Spring Boot 4.0은 단순히 &amp;ldquo;마이너한 기능 추가&amp;rdquo;가 아니라,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5741&quot; data-start=&quot;5592&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5643&quot; data-start=&quot;5592&quot;&gt;&lt;b&gt;플랫폼 세대 교체 (Framework 7, Java 25, 생태계 전체 버전 업)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;5688&quot; data-start=&quot;5644&quot;&gt;&lt;b&gt;코드 모듈화 + null-safety 강화로 장기적인 유지보수성 개선&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;5741&quot; data-start=&quot;5689&quot;&gt;&lt;b&gt;HTTP/Versioning/Observability/Test 같은 실전 기능 보강&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;5763&quot; data-start=&quot;5743&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Ref.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링부트 공식 Docs&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://spring.io/blog/2025/11/20/spring-boot-4-0-0-available-now&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://spring.io/blog/2025/11/20/spring-boot-4-0-0-available-now&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1763704101616&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Spring Boot 4.0.0 available now&quot; data-og-description=&quot;On behalf of the team and everyone who has contributed, I'm extremely happy to announce that Spring Boot 4.0.0 has been released and is now available from Maven Central. This release is the beginning of a new Spring Boot generation providing solid foundati&quot; data-og-host=&quot;spring.io&quot; data-og-source-url=&quot;https://spring.io/blog/2025/11/20/spring-boot-4-0-0-available-now&quot; data-og-url=&quot;https://spring.io/blog/2025/11/20/spring-boot-4-0-0-available-now&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gfMNY/hyZN7xRaqW/FIkZWd1tWMI0n3jqJaFeH1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bDqgtb/hyZNCydX5L/7PPwORqXptC97NwyicTAHK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://spring.io/blog/2025/11/20/spring-boot-4-0-0-available-now&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://spring.io/blog/2025/11/20/spring-boot-4-0-0-available-now&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gfMNY/hyZN7xRaqW/FIkZWd1tWMI0n3jqJaFeH1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bDqgtb/hyZNCydX5L/7PPwORqXptC97NwyicTAHK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot 4.0.0 available now&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;On behalf of the team and everyone who has contributed, I'm extremely happy to announce that Spring Boot 4.0.0 has been released and is now available from Maven Central. This release is the beginning of a new Spring Boot generation providing solid foundati&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링부트 github&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/spring-projects/spring-boot&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/spring-projects/spring-boot&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1763704219931&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - spring-projects/spring-boot: Spring Boot helps you to create Spring-powered, production-grade applications and services&quot; data-og-description=&quot;Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss. - spring-projects/spring-boot&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/spring-projects/spring-boot&quot; data-og-url=&quot;https://github.com/spring-projects/spring-boot&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/oQXQd/hyZObNMyuP/jpRKYbgDOUb6B3A0KWrcEK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/JPlyy/hyZOhAtnAH/Me9oYCIQ7Vk69V1aXz4Ti0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/spring-projects/spring-boot&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/spring-projects/spring-boot&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/oQXQd/hyZObNMyuP/jpRKYbgDOUb6B3A0KWrcEK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/JPlyy/hyZOhAtnAH/Me9oYCIQ7Vk69V1aXz4Ti0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - spring-projects/spring-boot: Spring Boot helps you to create Spring-powered, production-grade applications and services&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss. - spring-projects/spring-boot&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Spring</category>
      <category>4.0</category>
      <category>github</category>
      <category>spring</category>
      <category>SpringBoot</category>
      <category>스프링부트</category>
      <category>스프링부트4.0</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/53</guid>
      <comments>https://djlife.tistory.com/53#entry53comment</comments>
      <pubDate>Fri, 21 Nov 2025 15:07:31 +0900</pubDate>
    </item>
    <item>
      <title>chat gpt - 계속하려면 challenges.cloudflare.com 차단을 해제하십시오.</title>
      <link>https://djlife.tistory.com/52</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;527&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NIeXg/dJMcabihTrs/UK5f3zIGuOn4uuvNrDckP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NIeXg/dJMcabihTrs/UK5f3zIGuOn4uuvNrDckP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NIeXg/dJMcabihTrs/UK5f3zIGuOn4uuvNrDckP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNIeXg%2FdJMcabihTrs%2FUK5f3zIGuOn4uuvNrDckP0%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;682&quot; height=&quot;527&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;527&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2025-11-18&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;현재 chatGPT를 이용할 수 없습니다..  &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;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #0a0a0a; text-align: start;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAEQAA&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;클라우드플레어(Cloudflare)&lt;/span&gt;&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;웹사이트의 보안과 성능을 향상시키는 미국의 인터넷 서비스 기업입니다. 주요 서비스로는 CDN(콘텐츠 전송 네트워크), DDoS 공격 방어, 리버스 프록시, 무료 DNS 서비스(1.1.1.1) 등이 있으며, 개인과 기업 모두 인터넷의 속도, 안전성, 안정성을 높이는 데 사용됩니다.&lt;span data-processed=&quot;true&quot; data-wiz-uids=&quot;QsdgV_b,QsdgV_c,QsdgV_d&quot;&gt;&lt;span data-processed=&quot;true&quot; data-animation-atomic=&quot;&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: #001d35;&quot; data-processed=&quot;true&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #0a0a0a; text-align: start;&quot; data-processed=&quot;true&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;주요 서비스 및 기능&lt;span data-processed=&quot;true&quot; data-wiz-uids=&quot;QsdgV_k,QsdgV_l,QsdgV_m&quot;&gt;&lt;span data-processed=&quot;true&quot; data-animation-atomic=&quot;&quot;&gt;&lt;span style=&quot;color: #001d35;&quot; data-processed=&quot;true&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0a0a0a; text-align: start;&quot; data-processed=&quot;true&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAMQAA&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;보안:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;DDoS 공격, 악성 봇 등 다양한 위협으로부터 웹사이트를 보호합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAMQAQ&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;성능 향상:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;전 세계에 분산된 엣지 네트워크를 통해 콘텐츠를 사용자에게 더 가까운 위치에서 제공하여 속도를 높입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAMQAg&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;리버스 프록시:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;웹사이트와 사용자의 사이에 위치하여 트래픽을 보호하고 최적화합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAMQAw&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;무료 DNS 서비스 (1.1.1.1):&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;빠르고 안전하며 개인 정보를 중시하는 무료 DNS 서비스를 제공합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAMQBA&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;기타:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;SSL 인증, 도메인 등록, 애플리케이션 삽입 등 다양한 서비스를 제공합니다.&lt;/span&gt;&lt;span data-processed=&quot;true&quot; data-wiz-uids=&quot;QsdgV_13,QsdgV_14,QsdgV_15&quot;&gt;&lt;span data-processed=&quot;true&quot; data-animation-atomic=&quot;&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: #001d35;&quot; data-processed=&quot;true&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #0a0a0a; text-align: start;&quot; data-processed=&quot;true&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;누가 사용하나요?&lt;span data-processed=&quot;true&quot; data-wiz-uids=&quot;QsdgV_1d,QsdgV_1e,QsdgV_1f&quot;&gt;&lt;span data-processed=&quot;true&quot; data-animation-atomic=&quot;&quot;&gt;&lt;span style=&quot;color: #001d35;&quot; data-processed=&quot;true&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0a0a0a; text-align: start;&quot; data-processed=&quot;true&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAUQAA&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #e5edff;&quot;&gt;기업:&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #e5edff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클라우드, SaaS, 온프레미스 등 다양한 환경에서 복잡성을 줄이고 보안을 강화하기 위해 사용합니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAUQAQ&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #e5edff;&quot;&gt;개인:&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #e5edff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;블로거, 개인 웹사이트 운영자 등 인터넷 서비스를 제공하는 모든 사람이 사용할 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAUQAg&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #e5edff;&quot;&gt;특징:&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #e5edff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;웹사이트 트래픽이 많거나 DDoS 공격에 취약한 사이트들이 주로 이용합니다.&lt;/span&gt;&lt;/span&gt;&lt;span data-processed=&quot;true&quot; data-wiz-uids=&quot;QsdgV_1q,QsdgV_1r,QsdgV_1s&quot;&gt;&lt;span data-processed=&quot;true&quot; data-animation-atomic=&quot;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&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;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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://www.cloudflarestatus.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.cloudflarestatus.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1763471709586&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Cloudflare Status&quot; data-og-description=&quot;&quot; data-og-host=&quot;www.cloudflarestatus.com&quot; data-og-source-url=&quot;https://www.cloudflarestatus.com/&quot; data-og-url=&quot;https://www.cloudflarestatus.com/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.cloudflarestatus.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.cloudflarestatus.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Cloudflare Status&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.cloudflarestatus.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1143&quot; data-origin-height=&quot;856&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mRbK7/dJMcaaKrKF5/S8xxdqlmUtKe65sHUe9Cb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mRbK7/dJMcaaKrKF5/S8xxdqlmUtKe65sHUe9Cb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mRbK7/dJMcaaKrKF5/S8xxdqlmUtKe65sHUe9Cb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmRbK7%2FdJMcaaKrKF5%2FS8xxdqlmUtKe65sHUe9Cb1%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;1143&quot; height=&quot;856&quot; data-origin-width=&quot;1143&quot; data-origin-height=&quot;856&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>변소</category>
      <category>Ai</category>
      <category>ChatGPT</category>
      <category>CloudFlare</category>
      <category>서버</category>
      <category>클라우드플래어</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/52</guid>
      <comments>https://djlife.tistory.com/52#entry52comment</comments>
      <pubDate>Tue, 18 Nov 2025 22:16:37 +0900</pubDate>
    </item>
    <item>
      <title>[Java] String 은 왜 불변(Immutable)일까? ( feat. StringBuilder를 써야 하는 이유)</title>
      <link>https://djlife.tistory.com/51</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;211&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjRzwb/dJMcahbKIXZ/V9jJRDnREBp1dqufdLAKi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjRzwb/dJMcahbKIXZ/V9jJRDnREBp1dqufdLAKi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjRzwb/dJMcahbKIXZ/V9jJRDnREBp1dqufdLAKi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjRzwb%2FdJMcahbKIXZ%2FV9jJRDnREBp1dqufdLAKi1%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;211&quot; height=&quot;246&quot; data-origin-width=&quot;211&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코테 풀다가 한 번쯤 턱 맞는 포인트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/181940&quot;&gt;프로그래머스&lt;/a&gt; 같은 데서 이런 문제 한 번쯤 본 적 있을 거다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 &lt;code&gt;my_string&lt;/code&gt; 과 정수 &lt;code&gt;k&lt;/code&gt;가 주어질 때,&lt;br /&gt;&lt;code&gt;my_string&lt;/code&gt; 을 &lt;code&gt;k&lt;/code&gt;번 반복한 문자열을 return 하세요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분 처음에는 이렇게 짠다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public String solution(String my_string, int k) {
    String answer = &quot;&quot;;
    for (int i = 0; i &amp;lt; k; i++) {
        answer += my_string;
    }
    return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 몇 개 돌려보면 잘 동작하고, 길이도 작으면 제출해도 그냥 통과한다.&lt;br /&gt;근데 문자열 길이랑 k가 좀만 커지면 이런 코드 패턴이 진짜 성능 구멍이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 하나다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 의 String 은 &amp;ldquo;불변(immutable)&amp;rdquo; 이기 때문.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String 이 불변이라는 게 정확히 무슨 뜻인지&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;
&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1.String 이 불변이라는 말의 의미&lt;/b&gt;&lt;/h3&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 class=&quot;reasonml&quot;&gt;&lt;code&gt;String s = &quot;hello&quot;;  
s.toUpperCase();  
System.out.println(s); // hello  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 보면 여기서 한 번씩 당황한다.&lt;br /&gt;&amp;ldquo;대문자로 바꾸라고 했는데 왜 그대로지?&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;toUpperCase() 는 기존 String 을 수정하는 메서드가 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대문자로 변환된 새 String 객체 를 만들어서 리턴할 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;u&gt;원래 &quot;hello&quot; 라는 문자열 객체는 그대로 남아 있다.&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정상적인 사용은 이렇게 된다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;String s = &quot;hello&quot;;  
s = s.toUpperCase();  
System.out.println(s); // HELLO  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하면:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번 만들어진 String 객체의 내용은 절대 안 바뀐다.&lt;br /&gt;바뀌는 건 그 객체를 가리키는 변수 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 String 이 불변(immutable) 이라는 말의 의미다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;2. 왜 굳이 String 을 불변으로 만들었을까?&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;그냥 가변으로 만들어서 바꾸기 편하게 해주지&amp;hellip;&amp;rdquo; 싶은데,&lt;br /&gt;Java 쪽에서 일부러 불변으로 설계한 이유가 몇 가지 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1. 보안(Security)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String 은 이런 데 자주 쓰인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB 커넥션 URL, 사용자 ID, Password&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 경로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class 이름, 리플렉션 관련 문자열&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 주소, 각종 설정값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 String 이 가변이면,&lt;br /&gt;어딘가에서 참조를 들고 있다가 중간에 값을 바꿔버리는 것도 가능해진다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;String password = &quot;secret&quot;;  
// 다른 코드가 password 를 바꿔버릴 수 있다면?  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불변이면 이런 류의 공격 자체가 구조적으로 막힌다.&lt;br /&gt;한 번 만들어진 문자열의 내용은 누구도 바꿀 수 없기 때문.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-2. 스레드 안전(Thread-Safety)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티스레드 환경에서 여러 스레드가 같은 문자열을 공유하는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 URL&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 SQL 쿼리&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;br /&gt;하지만 String 은 불변이라서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 스레드가 동시에 읽기만 해도 안전 하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따로 synchronized 를 걸 필요도 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 JVM 내부, 라이브러리 내부에서도 String 을 마음 편하게 공유해서 쓴다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-3. String Pool &amp;amp; 캐싱&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 에는 String Pool(상수 풀) 이라는 개념이 있다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;String a = &quot;hello&quot;;  
String b = &quot;hello&quot;;  

System.out.println(a == b); // true (같은 객체)  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리터럴 &quot;hello&quot; 는 JVM 상수 풀에 한 번만 올라가고,&lt;br /&gt;같은 리터럴을 쓰는 변수는 그 객체를 재사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 가능한 이유도 String 이 불변이기 때문이다.&lt;br /&gt;누군가 &quot;hello&quot; 라는 문자열의 내용을 중간에 바꿔버릴 수 있다면,&lt;br /&gt;상수 풀이라는 개념이 성립할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 String 은 hashCode() 결과도 한 번 계산해두고 재사용한다.&lt;br /&gt;그래서 HashMap 의 key, HashSet 의 원소로 자주 쓰이는 것도 이 덕분이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3.불변이라서 생기는 성능 문제 &amp;ndash; 코테 예시로 보기&lt;/b&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;my_string 을 k번 반복해서 이어붙인 문자열을 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 짰던 코드:&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;public String solution(String my_string, int k) {  
    String answer = &quot;&quot;;  
    for (int i = 0; i &amp;lt; k; i++) {  
        answer += my_string;  
    }  
    return answer;  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;겉으로 보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 반복: &quot;&quot; + &quot;abc&quot; &amp;rarr; &quot;abc&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 반복: &quot;abc&quot; + &quot;abc&quot; &amp;rarr; &quot;abcabc&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 번째 반복: &quot;abcabc&quot; + &quot;abc&quot; &amp;rarr; &quot;abcabcabc&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 보이는데, 내부에서는 이런 일이 일어난다.&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;answer = answer + my_string;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 한 줄이 컴파일되면 실제로는 대략:&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;answer = new StringBuilder(answer)  
             .append(my_string)  
             .toString();&lt;/code&gt;&lt;/pre&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;기존 answer 내용을 전부 복사해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;my_string 을 뒤에 붙인 새 문자열을 만들고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그걸 다시 answer 에 대입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이가 커질수록 매번 더 긴 문자열을 계속 복사하는 구조라서&lt;br /&gt;결국 전체 시간 복잡도는 O(n&amp;sup2;) 쪽으로 간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열이 10개, 100개 이럴 때는 티가 안 나는데,&lt;br /&gt;길이 10만, 20만 이런 쪽으로 가면 이 차이가 바로 시간 초과로 튀어나온다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.StringBuilder 를 써야 하는 이유&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 문자열 누적할 때는 보통 이렇게 바꾼다.&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;public String solution(String my_string, int k) {  
    StringBuilder sb = new StringBuilder(my_string.length() * k);  
    for (int i = 0; i &amp;lt; k; i++) {  
        sb.append(my_string);  
    }  
    return sb.toString();  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;StringBuilder 는 내부에 char[] 버퍼를 하나 들고 있고,&lt;br /&gt;append() 할 때마다 그 버퍼에 글자를 채워 넣는 식으로 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버퍼가 부족해지면 가끔씩만 크게 확장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체적으로는 O(n) 에 가까운 시간 복잡도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;new StringBuilder(my_string.length() * k);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 capacity 를 미리 잡아두는 이유는,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 문자열 길이를 대략 알고 있으니까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에 버퍼 확장(reallocate) 이 거의 안 일어나게 하려는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코테에서 &amp;ldquo;문자열 이어붙이기&amp;rdquo; 계열 문제는&lt;br /&gt;이 패턴 하나만 붙잡고 있어도 웬만한 건 다 처리된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5.&amp;ldquo;컴파일러가 + 를 StringBuilder 로 바꿔준다면서?&amp;rdquo;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 컴파일러가 문자열 더하기를 최적화해 준다는 얘기도 많이 들을 거다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;String s = &quot;a&quot; + &quot;b&quot; + &quot;c&quot;;  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 컴파일할 때 대략 이렇게 바뀐다.&lt;/p&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;String s = new StringBuilder()  
        .append(&quot;a&quot;)  
        .append(&quot;b&quot;)  
        .append(&quot;c&quot;)  
        .toString();  &lt;/code&gt;&lt;/pre&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;pre class=&quot;matlab&quot;&gt;&lt;code&gt;String s = &quot;&quot;;  
for (int i = 0; i &amp;lt; n; i++) {  
    s = s + &quot;a&quot;;  
}  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 반복마다 다음처럼 바뀐다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;s = new StringBuilder(s)  
        .append(&quot;a&quot;)  
        .toString();  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 새로운 StringBuilder 를 만들고,&lt;br /&gt;이전 문자열 전체를 복사하고, 새 String 을 만들고&amp;hellip; 이게 반복된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 실질적인 가이드는 이렇게 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 줄 안에서 &quot;a&quot; + &quot;b&quot; + &quot;c&quot;&lt;br /&gt;&amp;rarr; 컴파일러가 알아서 최적화해주니 괜찮다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복문 안에서 문자열 누적 (+=, s = s + ...)&lt;br /&gt;&amp;rarr; 성능 구멍이 될 수 있으니 무조건 StringBuilder 를 쓰는 게 안전하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6.Java 11 이상이라면 repeat() 도 있다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 조건이 &amp;ldquo;문자열을 k번 반복해서 이어붙여라&amp;rdquo; 딱 이 정도면,&lt;br /&gt;Java 11 이상에서는 아예 메서드가 준비돼 있다.&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;public String solution(String my_string, int k) {  
    return my_string.repeat(k);  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 구현도 결국 StringBuilder 비슷한 방식으로 효율적으로 동작하기 때문에,&lt;br /&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;Java 11+ : my_string.repeat(k);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 8 기준 : StringBuilder + append 반복&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;7.불변이라서 생기는 또 다른 함정들&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불변이라는 특성 때문에 자주 헷갈리는 부분 몇 개만 정리해 둔다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;7-1. 문자열 메서드들은 전부 &amp;ldquo;새 String 반환&amp;rdquo;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드를 보자.&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;String s = &quot; hello &quot;;  

s.trim();  
s.toUpperCase();  
s.replace(&quot;H&quot;, &quot;J&quot;);  

System.out.println(s); // &quot; hello &quot;  &lt;/code&gt;&lt;/pre&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;pre class=&quot;erlang&quot;&gt;&lt;code&gt;trim(), toUpperCase(), replace() 전부  &lt;/code&gt;&lt;/pre&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;pre class=&quot;makefile&quot;&gt;&lt;code&gt;String s = &quot; hello &quot;;  

s = s.trim();             // &quot;hello&quot;  
s = s.toUpperCase();      // &quot;HELLO&quot;  
s = s.replace(&quot;H&quot;, &quot;J&quot;);  // &quot;JELLO&quot;  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체이닝해도 마찬가지다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;String s = &quot; hello &quot;;  
s = s.trim()  
     .toUpperCase()  
     .replace(&quot;H&quot;, &quot;J&quot;);  &lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-2. substring 도 동일&lt;/h3&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;String s = &quot;abcdef&quot;;  
String sub = s.substring(0, 3); // &quot;abc&quot;  

System.out.println(s);   // &quot;abcdef&quot;  
System.out.println(sub); // &quot;abc&quot;  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;substring() 이 원본을 자르는 게 아니라,&lt;br /&gt;잘라진 부분만 따로 담은 새 String 을 만들어준다고 생각하면 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;8.코테/실무에서 String 불변 때문에 생기는 패턴 정리&lt;/b&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;반복문에서 문자열 누적 &amp;rarr; 무조건 StringBuilder&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;StringBuilder sb = new StringBuilder();  
for (...) {  
    sb.append(...);  
}  
String result = sb.toString();  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 많이 하는 백준/프로그래머스 스타일 문제&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;StringBuilder sb = new StringBuilder();  
for (int i = 0; i &amp;lt; n; i++) {  
    // 로직  
    sb.append(result).append('\\n');  
}  

System.out.print(sb);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 반복 (my_string, k 문제 같은 것)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 11 이상: my_string.repeat(k)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 8 기준: StringBuilder 로 직접 반복&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 조작 메서드들은 전부 &amp;ldquo;새 객체 반환&amp;rdquo;이라는 걸 항상 기억하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;trim, toUpperCase, toLowerCase, replace, substring &amp;hellip;&lt;/p&gt;
&lt;p 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;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;9.마무리&lt;/b&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;String 은 한 번 만들어지면 안 바뀐다.&lt;br /&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;span style=&quot;color: #ef6f53;&quot;&gt;반복문에서 문자열 누적 시 StringBuilder 써라&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;많이 반복되는 문자열은 capacity 미리 잡아라&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;문자열 메서드는 항상 &amp;ldquo;새 String&amp;rdquo; 을 리턴한다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 정도만 붙여두면,&lt;br /&gt;코테에서도 시간초과 덜 나고 실무 코드에서도 의미 없이 느린 문자열 처리 코드를 피할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 기회 되면 여기서 파생되는 주제들&lt;br /&gt;(예: String Pool, intern(), == vs equals() 비교 등)&lt;br /&gt;따로 빼서 면접 대비용으로 정리해도 괜찮을 것 같다.&lt;/p&gt;
&lt;pre class=&quot;tex&quot;&gt;&lt;code&gt;::contentReference\[oaicite:0\]{index=0}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Develop/Back-End</category>
      <category>immutable</category>
      <category>Java</category>
      <category>String</category>
      <category>불변</category>
      <category>코딩테스트</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/51</guid>
      <comments>https://djlife.tistory.com/51#entry51comment</comments>
      <pubDate>Mon, 17 Nov 2025 15:32:10 +0900</pubDate>
    </item>
    <item>
      <title>구 레거시 윈도우 서버 프로젝트 (IIS / ASP) 이관 도전기</title>
      <link>https://djlife.tistory.com/50</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;277&quot; data-origin-height=&quot;27&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpgIjs/btsPDHbDorw/BkpshZK79ZBhAXkmvPcKGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpgIjs/btsPDHbDorw/BkpshZK79ZBhAXkmvPcKGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpgIjs/btsPDHbDorw/BkpshZK79ZBhAXkmvPcKGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpgIjs%2FbtsPDHbDorw%2FBkpshZK79ZBhAXkmvPcKGk%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;277&quot; height=&quot;27&quot; data-origin-width=&quot;277&quot; data-origin-height=&quot;27&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;224&quot; data-origin-height=&quot;25&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JS7XH/btsPCk2KEVC/EWp85Qbjbgpufldwh9NpRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JS7XH/btsPCk2KEVC/EWp85Qbjbgpufldwh9NpRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JS7XH/btsPCk2KEVC/EWp85Qbjbgpufldwh9NpRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJS7XH%2FbtsPCk2KEVC%2FEWp85Qbjbgpufldwh9NpRK%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;224&quot; height=&quot;25&quot; data-origin-width=&quot;224&quot; data-origin-height=&quot;25&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;276&quot; data-start=&quot;270&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;목차&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;412&quot; data-start=&quot;277&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;293&quot; data-start=&quot;277&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이관 개요 및 환경 정리&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;310&quot; data-start=&quot;294&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사전 준비 (백업/점검)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;326&quot; data-start=&quot;311&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IIS 설정 백업 방법&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;347&quot; data-start=&quot;327&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹사이트 파일/데이터베이스 이전&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;373&quot; data-start=&quot;348&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IIS 설정 복원 및 재구성 (2012)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;395&quot; data-start=&quot;374&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;테스트 및 마이그레이션 체크리스트&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;412&quot; data-start=&quot;396&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;FAQ &amp;amp; 문제 해결 팁&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;438&quot; data-start=&quot;419&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. 이관 개요 및 환경 정리&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;630&quot; data-start=&quot;440&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;498&quot; data-start=&quot;440&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;이관 전 서버&lt;/b&gt;: Windows Server 2008 R2 Enterprise (IIS 7.5)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;552&quot; data-start=&quot;499&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;이관 후 서버&lt;/b&gt;: Windows Server 2012 Standard (IIS 8.0)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;582&quot; data-start=&quot;553&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;목적&lt;/b&gt;: 특정 사이트만 이전 (전체가 아님)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;630&quot; data-start=&quot;583&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;주요 서비스&lt;/b&gt;: ASP/ASP.NET 웹사이트, MSSQL 연동, FTP 등&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;656&quot; data-start=&quot;637&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. 사전 준비 (백업/점검)&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;669&quot; data-start=&quot;658&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;체크리스트&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;932&quot; data-start=&quot;670&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;703&quot; data-start=&quot;670&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;웹사이트 파일 백업&lt;/b&gt; (웹 루트 폴더 전체)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;756&quot; data-start=&quot;704&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;IIS 설정 백업&lt;/b&gt; (ApplicationHost.config/메타베이스 등)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;793&quot; data-start=&quot;757&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;DB 백업&lt;/b&gt; (필요 시 .bak, 또는 DUMP)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;820&quot; data-start=&quot;794&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;SSL 인증서 백업&lt;/b&gt; (필요시)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;860&quot; data-start=&quot;821&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;방화벽/포트 확인&lt;/b&gt; (HTTP/HTTPS, FTP 등)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;886&quot; data-start=&quot;861&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;서버 IP/도메인 정보 메모&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;932&quot; data-start=&quot;887&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Windows Update&lt;/b&gt; (신규 서버에 최신 보안 패치 적용)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;945&quot; data-start=&quot;934&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;상세 설명&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1021&quot; data-start=&quot;946&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;981&quot; data-start=&quot;946&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;백업은 두 번! (실제 복사, 그리고 자동화 스크립트/도구)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1021&quot; data-start=&quot;982&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;운영 중인 사이트라면 &lt;b&gt;이관 시점&lt;/b&gt;을 사전에 정해두는 것이 안전&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;1046&quot; data-start=&quot;1028&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. IIS 설정 백업 방법&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;1086&quot; data-start=&quot;1048&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3-1. ApplicationHost.config 내보내기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1140&quot; data-start=&quot;1087&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;(IIS 7.0 이상은 메타베이스 대신 ApplicationHost.config 기반임)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753836274806&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# PowerShell을 '관리자 권한'으로 실행 
cd &quot;C:\Windows\System32\inetsrv&quot; 
appcmd add backup myBackup&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;myBackup은&amp;nbsp;백업명&amp;nbsp;(원하는&amp;nbsp;이름으로&amp;nbsp;변경&amp;nbsp;가능) &lt;br /&gt;결과물:&amp;nbsp;C:\Windows\System32\inetsrv\backup\myBackup\&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1369&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3-2. 사이트별 구성 내보내기 (특정 사이트만)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1378&quot; data-start=&quot;1370&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사이트명 확인:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753836539685&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;appcmd list site&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1428&quot; data-start=&quot;1414&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1428&quot; data-start=&quot;1414&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;특정 사이트만 내보내려면:&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753836554437&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;appcmd list site &quot;사이트명&quot; /config /xml &amp;gt; D:\Backup\site_config.xml&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-end=&quot;1534&quot; data-start=&quot;1513&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3-3. 웹사이트 파일 백업&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1593&quot; data-start=&quot;1535&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1574&quot; data-start=&quot;1535&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일반적으로 C:\inetpub\wwwroot\ 또는 커스텀 경로&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1593&quot; data-start=&quot;1575&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당 사이트 루트 전체 복사:&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753836570157&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;robocopy &quot;C:\inetpub\wwwroot\YourSite&quot; &quot;D:\Backup\YourSite&quot; /E&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1698&quot; data-start=&quot;1675&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1698&quot; data-start=&quot;1675&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;FTP 등 별도 서비스 폴더도 동일하게&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1721&quot; data-start=&quot;1700&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3-4. SSL 인증서 백업&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1780&quot; data-start=&quot;1722&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1752&quot; data-start=&quot;1722&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;인증서 MMC에서 내보내기(개인키 포함, .pfx)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1780&quot; data-start=&quot;1753&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IIS 관리 콘솔 &amp;rarr; 서버 인증서 &amp;rarr; 내보내기&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;1810&quot; data-start=&quot;1787&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4. 웹사이트 파일/데이터베이스 이전&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1902&quot; data-start=&quot;1812&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1839&quot; data-start=&quot;1812&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;백업해둔 웹사이트 폴더를 신규 서버로 복사&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1879&quot; data-start=&quot;1840&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DB는 .bak 파일로 복원하거나, Export/Import&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1902&quot; data-start=&quot;1880&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;SSL 인증서는 MMC로 Import&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;1937&quot; data-start=&quot;1909&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5. IIS 설정 복원 및 재구성 (2012)&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;1967&quot; data-start=&quot;1939&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5-1. IIS 역할 및 필요 컴포넌트 설치&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2075&quot; data-start=&quot;1968&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1998&quot; data-start=&quot;1968&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IIS 설치 (서버 관리자 &amp;rarr; 역할 및 기능 추가)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2033&quot; data-start=&quot;1999&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ASP/ASP.NET, CGI 등 필요한 구성요소 추가&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2075&quot; data-start=&quot;2034&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;32비트 지원(필요시), ISAPI, Windows 인증 등 옵션 확인&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2096&quot; data-start=&quot;2077&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5-2. 사이트 Import&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2126&quot; data-start=&quot;2097&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;(전체 백업/복원이 아니라면 수동 등록 추천)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-end=&quot;2161&quot; data-start=&quot;2128&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;A. ApplicationHost.config 복원&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2177&quot; data-start=&quot;2162&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2177&quot; data-start=&quot;2162&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;전체 환경 복원 필요시:&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753836635285&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;appcmd restore backup myBackup&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2276&quot; data-start=&quot;2227&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2276&quot; data-start=&quot;2227&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;주의:&lt;/b&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;전체 복원&lt;/b&gt;은 &lt;b&gt;기존 설정&lt;/b&gt;을 덮어씌우니 &lt;b&gt;신규 서버&lt;/b&gt;에서 조심히 &lt;b&gt;테스트&lt;/b&gt;할 것!&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;2295&quot; data-start=&quot;2278&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;B. 사이트 개별 등록&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2483&quot; data-start=&quot;2296&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2318&quot; data-start=&quot;2296&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IIS 관리자에서 &amp;lsquo;사이트 추가&amp;rsquo;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2357&quot; data-start=&quot;2319&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;포트/호스트헤더/인증/애플리케이션 풀 등 원본과 동일하게 구성&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2417&quot; data-start=&quot;2358&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;site_config.xml 직접 Import는 지원 안 하므로, GUI에서 수동 입력이 일반적&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2483&quot; data-start=&quot;2418&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Application Pool은 .NET 버전/모드(Integrated/Classic), 32비트 지원 여부 확인&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;2503&quot; data-start=&quot;2485&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;C. SSL 인증서 설치&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2552&quot; data-start=&quot;2504&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2526&quot; data-start=&quot;2504&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;인증서 MMC &amp;rarr; 인증서 가져오기&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2552&quot; data-start=&quot;2527&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IIS 관리 콘솔에서 바인딩에 인증서 연결&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;2587&quot; data-start=&quot;2554&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;D. hosts 파일 등 도메인 매핑(테스트 목적)&lt;/span&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;2618&quot; data-start=&quot;2594&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;6. 테스트 및 마이그레이션 체크리스트&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2827&quot; data-start=&quot;2620&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2651&quot; data-start=&quot;2620&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사이트 정상 동작 여부 (HTTP/HTTPS)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2674&quot; data-start=&quot;2652&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DB 연결 및 쿼리 정상 작동&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2708&quot; data-start=&quot;2675&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파일 업로드/다운로드, 세션, 쿠키 등 정상 여부&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2739&quot; data-start=&quot;2709&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이벤트 로그 오류 여부 확인 (이벤트 뷰어)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2762&quot; data-start=&quot;2740&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;외부 접근성 (방화벽, 포트)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2794&quot; data-start=&quot;2763&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;관리자 페이지/FTP 등 부가 서비스 정상여부&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2827&quot; data-start=&quot;2795&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;백업/복원 시 권한 문제(권한 상속/계정) 체크&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;2853&quot; data-start=&quot;2834&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;7. FAQ &amp;amp; 문제 해결 팁&lt;/span&gt;&lt;/h2&gt;
&lt;p data-end=&quot;3143&quot; data-start=&quot;2855&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Q1. 백업한 appcmd 설정이 바로 Import가 안될 때?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr; 2008R2와 2012는 구조상 거의 동일하지만, 일부 컴포넌트/경로 차이로 인해 직접 GUI에서 재등록이 더 안전&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Q2. 인증서 내보내기 오류&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr; 인증서 MMC에서 &amp;lsquo;개인키 포함&amp;rsquo; 옵션 반드시 체크&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Q3. 권한 오류&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr; 웹 루트 폴더는 IIS_IUSRS, NETWORK SERVICE에 읽기/쓰기 권한 필요&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Q4. 바인딩 충돌&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr; 기존과 동일한 포트 사용시 중복에 유의 (특히 80, 443)&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;3143&quot; data-start=&quot;2855&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Q5. 전체 구성 백업과 사이트별 구성 내보내기 차이&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr; 전체 백업/롤백용, 사이트별 내보내기는 부분 이관/문서화용&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&gt;&lt;b&gt;백업 범위&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;IIS 전체&lt;/td&gt;
&lt;td&gt;지정한 사이트(1개)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;용도&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;전체 환경 복구/마이그레이션&lt;/td&gt;
&lt;td&gt;특정 사이트만 복구/이관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;복원 방법&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;appcmd restore backup&lt;/td&gt;
&lt;td&gt;수동 생성 참고자료&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;실제 파일&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;시스템 폴더에 저장&lt;/td&gt;
&lt;td&gt;원하는 경로에 XML로 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;일반적 활용&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;서버 전체 백업/롤백&lt;/td&gt;
&lt;td&gt;일부 사이트 백업/이관&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;3345&quot; data-start=&quot;3338&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;참고자료&amp;nbsp; Ref.&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3651&quot; data-start=&quot;3346&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3402&quot; data-start=&quot;3346&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; data-end=&quot;3402&quot; data-start=&quot;3348&quot;&gt;공식 MS IIS 문서&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;3516&quot; data-start=&quot;3403&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; data-end=&quot;3516&quot; data-start=&quot;3405&quot;&gt;appcmd 명령어 참고&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/iis/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learn.microsoft.com/ko-kr/iis/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753835306315&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;IIS 설명서&quot; data-og-description=&quot;IIS에 대해 알아봅니다.&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/ko-kr/iis/&quot; data-og-url=&quot;https://learn.microsoft.com/ko-kr/iis/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/EPkCx/hyZq1StUNV/AFa8KfWbqNYb0WyW9CeX81/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/iis/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/ko-kr/iis/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/EPkCx/hyZq1StUNV/AFa8KfWbqNYb0WyW9CeX81/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;IIS 설명서&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;IIS에 대해 알아봅니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/iis/get-started/getting-started-with-iis/getting-started-with-appcmdexe&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learn.microsoft.com/en-us/iis/get-started/getting-started-with-iis/getting-started-with-appcmdexe&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753835284437&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Getting Started with AppCmd.exe&quot; data-og-description=&quot;AppCmd.exe is the single command line tool for managing IIS 7 and above. It exposes all key server management functionality through a set of intuitive manage...&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/en-us/iis/get-started/getting-started-with-iis/getting-started-with-appcmdexe&quot; data-og-url=&quot;https://learn.microsoft.com/en-us/iis/get-started/getting-started-with-iis/getting-started-with-appcmdexe&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DxNXl/hyZqVdEwon/UbyuSFFOKkFsQ6nKNyVjV1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/iis/get-started/getting-started-with-iis/getting-started-with-appcmdexe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/en-us/iis/get-started/getting-started-with-iis/getting-started-with-appcmdexe&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DxNXl/hyZqVdEwon/UbyuSFFOKkFsQ6nKNyVjV1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Getting Started with AppCmd.exe&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;AppCmd.exe is the single command line tool for managing IIS 7 and above. It exposes all key server management functionality through a set of intuitive manage...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;
&lt;blockquote data-end=&quot;3770&quot; data-start=&quot;3658&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;3770&quot; data-start=&quot;3660&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;실무에서 가장 많이 발생하는 이슈는 &lt;b&gt;권한/경로 문제, SSL 인증서 이슈&lt;/b&gt;와 &lt;b&gt;서버간 Application Pool 호환성&lt;/b&gt;이니 반드시 체크리스트 기반으로 차근차근 진행하는 게 안전하다  &lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/DevOps</category>
      <category>IIS</category>
      <category>window server</category>
      <category>마이그레이션</category>
      <category>웹서버</category>
      <category>웹서버 마이그레이션</category>
      <category>윈도우서버</category>
      <category>윈도우서버 마이그레이션 가이드</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/50</guid>
      <comments>https://djlife.tistory.com/50#entry50comment</comments>
      <pubDate>Wed, 30 Jul 2025 09:52:04 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot + MyBatis 쿼리 파라미터 자동 로깅 라이브러리 개발 후기 &amp;quot; mybatis-query-logger &amp;quot;  </title>
      <link>https://djlife.tistory.com/49</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;88&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/delCOr/btsPF2849oP/KgvVpigRqFRB8N8vZa19Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/delCOr/btsPF2849oP/KgvVpigRqFRB8N8vZa19Ck/img.png&quot; data-alt=&quot;mybatis&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/delCOr/btsPF2849oP/KgvVpigRqFRB8N8vZa19Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdelCOr%2FbtsPF2849oP%2FKgvVpigRqFRB8N8vZa19Ck%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;350&quot; height=&quot;88&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;88&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;mybatis&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;Spring Boot + MyBatis 쿼리 자동 로깅 라이브러리 개발기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 내가 처음으로 만들어 본 오픈소스 라이브러리인 MyBatis Query Logger를 소개 하려고 한다. 실무에서 MyBatis를 사용하면서 쿼리와 파라미터를 로깅하는 데 번거로움을 느꼈고, 이를 해결하고자 인터셉터 기반의 로깅 도구를 직접 제작하게 되었다.  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;라이브러리 소개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MyBatis Query Logger는 다음과 같은 기능을 제공한다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL 쿼리 자동 로깅&lt;/li&gt;
&lt;li&gt;바인딩된 파라미터 이름 및 값 출력&lt;/li&gt;
&lt;li&gt;실행 시간(ms) 측정 및 &lt;b&gt;느린 쿼리(Slow Query)&lt;/b&gt; 감지&lt;/li&gt;
&lt;li&gt;SLF4J 또는 System.out.println 중 선택 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Spring Boot 자동 설정 지원&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;설치 방법&lt;/h2&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;dependencies {
    implementation 'com.github.DongJu-Na:mybatis-query-logger:0.1.4'
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;# application.yml 설정 예시
mybatis-query-logger:
  enabled: true
  use-slf4j: true
  slow-query-threshold-ms: 1000
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;pre class=&quot;routeros&quot;&gt;&lt;code&gt;====== MyBatisQueryLogger ======
SQL:
SELECT * FROM USERS WHERE ID = ?
PARAMETERS:
id = 1 (Integer)
DURATION: 5ms
================================
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;느린 쿼리 감지&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정한 임계값(slow-query-threshold-ms)을 초과할 경우 다음 메시지가 함께 출력된다:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;SLOW QUERY DETECTED! Threshold: 1000ms
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;구현 포인트&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Intercepts 어노테이션을 통해 MyBatis StatementHandler의 prepare 메서드를 감쌌다.&lt;/li&gt;
&lt;li&gt;BoundSql 객체를 활용하여 SQL 문자열과 바인딩된 파라미터 목록을 추출한다.&lt;/li&gt;
&lt;li&gt;파라미터 타입은 Map, DTO, null 등 다양한 상황을 고려하여 리플렉션 기반으로 추출하고 있다.&lt;/li&gt;
&lt;li&gt;로깅 여부와 출력 방식은 application.yml 설정으로 제어할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;배운 점 및 느낀 점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot에서의 자동 설정 구조, MyBatis 인터셉터 구조, JitPack을 통한 Maven 배포 등 다양한 요소를 처음 다뤄봤다. 실제 현업에서도 유용하게 쓸 수 있고, 다른 개발자들도 편하게 사용할 수 있도록 문서화와 설정 확장에도 신경을 썼다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;앞으로의 개선 계획&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그 출력 포맷 개선 (멀티라인 &amp;rarr; 단일라인 등)&lt;/li&gt;
&lt;li&gt;파라미터 JSON 포맷 출력 옵션&lt;/li&gt;
&lt;li&gt;LogLevel 설정 기능 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;
&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;GitHub Issue&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitHub 저장소: &lt;a href=&quot;https://github.com/DongJu-Na/mybatis-query-logger&quot;&gt;https://github.com/DongJu-Na/mybatis-query-logger&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Build Log : &lt;a href=&quot;https://jitpack.io/#DongJu-Na/mybatis-query-logger/v0.0.8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jitpack.io/#DongJu-Na/mybatis-query-logger/0.1.4&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;함께 읽어볼만한 게시물들..&lt;/b&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;&quot;&gt;&lt;a style=&quot;color: #333333;&quot;&gt;MyBatis 공식 문서 - 플러그인&lt;/a&gt; &amp;rarr; @Intercepts, @Signature 어노테이션 설명 포함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a href=&quot;https://mybatis.org/mybatis-3/ko/configuration.html#plugins&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mybatis.org/mybatis-3/ko/configuration.html#plugins&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1749439741965&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;마이바티스 3 | 매퍼 설정  &amp;ndash; mybatis&quot; data-og-description=&quot;매퍼 설정 마이바티스 XML 설정파일은 다양한 설정과 프로퍼티를 가진다. 문서의 구조는 다음과 같다.: configuration properties 이 설정은 외부에 옮길 수 있다. 자바 프로퍼티 파일 인스턴스에 설정할&quot; data-og-host=&quot;mybatis.org&quot; data-og-source-url=&quot;https://mybatis.org/mybatis-3/ko/configuration.html#plugins&quot; data-og-url=&quot;https://mybatis.org/mybatis-3/ko/configuration.html#plugins&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://mybatis.org/mybatis-3/ko/configuration.html#plugins&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mybatis.org/mybatis-3/ko/configuration.html#plugins&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;마이바티스 3 | 매퍼 설정 &amp;ndash; mybatis&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;매퍼 설정 마이바티스 XML 설정파일은 다양한 설정과 프로퍼티를 가진다. 문서의 구조는 다음과 같다.: configuration properties 이 설정은 외부에 옮길 수 있다. 자바 프로퍼티 파일 인스턴스에 설정할&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mybatis.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&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;&quot;&gt;&lt;a style=&quot;color: #333333;&quot;&gt;MyBatis BoundSql 객체 설명&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://mybatis.org/mybatis-3/ko/java-api.html#BoundSql&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mybatis.org/mybatis-3/ko/java-api.html#BoundSql&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1749439614376&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;마이바티스 3 | 자바 API &amp;ndash; mybatis&quot; data-og-description=&quot;자바 API 이제 마이바티스를 설정하는 방법과 매핑을 만드는 방법을 알게 되었다. 이미 충분히 잘 사용할 준비가 된 셈이다. 마이바티스 자바 API 는 당신의 노력에 대한 보상을 얻게 할 것이다. JD&quot; data-og-host=&quot;mybatis.org&quot; data-og-source-url=&quot;https://mybatis.org/mybatis-3/ko/java-api.html#BoundSql&quot; data-og-url=&quot;https://mybatis.org/mybatis-3/ko/java-api.html#BoundSql&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://mybatis.org/mybatis-3/ko/java-api.html#BoundSql&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mybatis.org/mybatis-3/ko/java-api.html#BoundSql&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;마이바티스 3 | 자바 API &amp;ndash; mybatis&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;자바 API 이제 마이바티스를 설정하는 방법과 매핑을 만드는 방법을 알게 되었다. 이미 충분히 잘 사용할 준비가 된 셈이다. 마이바티스 자바 API 는 당신의 노력에 대한 보상을 얻게 할 것이다. JD&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mybatis.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a style=&quot;color: #333333;&quot;&gt;MyBatis Spring Boot Starter 문서&lt;/a&gt; &amp;rarr; ConfigurationCustomizer 등록 방식&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1749439785218&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Introduction &amp;ndash; mybatis-spring-boot-autoconfigure&quot; data-og-description=&quot;Using the SpringBootVFS The MyBatis-Spring-Boot-Starter provides the SpringBootVFS as an implementation class of VFS. The VFS is used for searching classes (e.g. target class of type alias, type handler class) from an application (or application server). I&quot; data-og-host=&quot;mybatis.org&quot; data-og-source-url=&quot;https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/&quot; data-og-url=&quot;https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Introduction &amp;ndash; mybatis-spring-boot-autoconfigure&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Using the SpringBootVFS The MyBatis-Spring-Boot-Starter provides the SpringBootVFS as an implementation class of VFS. The VFS is used for searching classes (e.g. target class of type alias, type handler class) from an application (or application server). I&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mybatis.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;&quot;&gt;Spring&amp;nbsp;Boot&amp;nbsp;공식&amp;nbsp;문서&amp;nbsp;-&amp;nbsp;Externalized&amp;nbsp;Configuration&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/appendix/application-properties/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.spring.io/spring-boot/appendix/application-properties/index.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1749439837391&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Common Application Properties :: Spring Boot&quot; data-og-description=&quot;&quot; data-og-host=&quot;docs.spring.io&quot; data-og-source-url=&quot;https://docs.spring.io/spring-boot/appendix/application-properties/index.html&quot; data-og-url=&quot;https://docs.spring.io/spring-boot/appendix/application-properties/index.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/appendix/application-properties/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.spring.io/spring-boot/appendix/application-properties/index.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Common Application Properties :: Spring Boot&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a style=&quot;color: #333333;&quot;&gt;JitPack 문서 - Gradle 설정&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jitpack.io/docs/#gradle&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jitpack.io/docs/#gradle&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1749439860030&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;:: Documentation for JitPack.io&quot; data-og-description=&quot;JitPack.io JitPack is a novel package repository for JVM and Android projects. It builds Git projects on demand and provides you with ready-to-use artifacts (jar, aar). If you want your library to be available to the world, there is no need to go through p&quot; data-og-host=&quot;docs.jitpack.io&quot; data-og-source-url=&quot;https://jitpack.io/docs/#gradle&quot; data-og-url=&quot;https://docs.jitpack.io&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://jitpack.io/docs/#gradle&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jitpack.io/docs/#gradle&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;:: Documentation for JitPack.io&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;JitPack.io JitPack is a novel package repository for JVM and Android projects. It builds Git projects on demand and provides you with ready-to-use artifacts (jar, aar). If you want your library to be available to the world, there is no need to go through p&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.jitpack.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&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;&quot;&gt;&lt;a style=&quot;color: #333333;&quot;&gt;SLF4J 공식문서&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://www.slf4j.org/docs.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.slf4j.org/docs.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1749439923983&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;SLF4J Documentation&quot; data-og-description=&quot;Documentation Given the small size of SLF4J, its documentation is not very lengthy. Videos&quot; data-og-host=&quot;www.slf4j.org&quot; data-og-source-url=&quot;https://www.slf4j.org/docs.html&quot; data-og-url=&quot;https://www.slf4j.org/docs.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.slf4j.org/docs.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.slf4j.org/docs.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SLF4J Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Documentation Given the small size of SLF4J, its documentation is not very lengthy. Videos&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.slf4j.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&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;
&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>인디해커</category>
      <category>mybatis</category>
      <category>mybatis-query-logger</category>
      <category>query</category>
      <category>spring boot</category>
      <category>스프링부트</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/49</guid>
      <comments>https://djlife.tistory.com/49#entry49comment</comments>
      <pubDate>Mon, 9 Jun 2025 12:19:38 +0900</pubDate>
    </item>
    <item>
      <title>[nssm] 윈도우(window)에서 JAR 파일 서비스로 등록하기  </title>
      <link>https://djlife.tistory.com/48</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2350&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eCRtLN/btsNuHzESPR/01pPzUkuWYvk1agVDdm67k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eCRtLN/btsNuHzESPR/01pPzUkuWYvk1agVDdm67k/img.png&quot; data-alt=&quot;nssm&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eCRtLN/btsNuHzESPR/01pPzUkuWYvk1agVDdm67k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeCRtLN%2FbtsNuHzESPR%2F01pPzUkuWYvk1agVDdm67k%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;2350&quot; height=&quot;348&quot; data-origin-width=&quot;2350&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;nssm&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;nssm&amp;nbsp;(Non-Sucking&amp;nbsp;Service&amp;nbsp;Manager)&lt;/b&gt;은 Windows 환경에서 Java 애플리케이션이나 기타 실행 파일을 Windows 서비스처럼 등록해서 관리할 수 있게 해주는 매우 실용적인 도구  &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;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;인프라가 열악하여&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;api 서버를 스테이션 남는거에 돌리고 있는데&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;/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;도커를 사용하다가 윈도우에서는 너무 무겁고&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;그래서 찾다가 발견된 nssm !!!!!  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;1303&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v30Fm/btsNwbt6aEQ/cL70JmHWJ4kcx4OI9MHfi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v30Fm/btsNwbt6aEQ/cL70JmHWJ4kcx4OI9MHfi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v30Fm/btsNwbt6aEQ/cL70JmHWJ4kcx4OI9MHfi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv30Fm%2FbtsNwbt6aEQ%2FcL70JmHWJ4kcx4OI9MHfi0%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;1689&quot; height=&quot;1303&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;1303&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 커맨드로 nssm.exe를 실행해보면 ( nssm.exe 파일이 있는 경로에서 실행!)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;-help 명령어와 같이 프로그램 커맨드에 대한 설명이 나온다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 설명은 &lt;b&gt;공식문서&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 서비스 등록 명령어 입력 시 gui 창과 함께 설정 할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1745463566545&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.\nssm.exe install FS-Service&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSdTe6/btsNxo6ypx0/WsL1R5R1GUnPAkAiCyQ4uk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSdTe6/btsNxo6ypx0/WsL1R5R1GUnPAkAiCyQ4uk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSdTe6/btsNxo6ypx0/WsL1R5R1GUnPAkAiCyQ4uk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSdTe6%2FbtsNxo6ypx0%2FWsL1R5R1GUnPAkAiCyQ4uk%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;642&quot; height=&quot;334&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;334&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;433&quot; data-start=&quot;420&quot; data-ke-size=&quot;size26&quot;&gt;✅ NSSM의 장점&lt;/h2&gt;
&lt;div&gt;&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;
&lt;div&gt;&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;899&quot; data-start=&quot;435&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;899&quot; data-start=&quot;463&quot;&gt;
&lt;tr data-end=&quot;511&quot; data-start=&quot;463&quot;&gt;
&lt;td data-end=&quot;482&quot; data-start=&quot;463&quot;&gt;  &lt;b&gt;자동 재시작 지원&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;511&quot; data-start=&quot;482&quot;&gt;서비스가 비정상 종료될 경우 자동 재시작 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;578&quot; data-start=&quot;512&quot;&gt;
&lt;td data-end=&quot;535&quot; data-start=&quot;512&quot;&gt;  &lt;b&gt;부팅 시 자동 시작 가능&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;578&quot; data-start=&quot;535&quot;&gt;Windows 서비스로 등록되기 때문에 시스템 부팅 후 자동 실행 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;646&quot; data-start=&quot;579&quot;&gt;
&lt;td data-end=&quot;600&quot; data-start=&quot;579&quot;&gt;  &lt;b&gt;보안 계정 지정 가능&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;646&quot; data-start=&quot;600&quot;&gt;특정 사용자 권한으로 서비스 실행 가능 (예: 도메인 계정, 로컬 계정 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;704&quot; data-start=&quot;647&quot;&gt;
&lt;td data-end=&quot;667&quot; data-start=&quot;647&quot;&gt;  &lt;b&gt;작업 디렉토리 지정&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;704&quot; data-start=&quot;667&quot;&gt;애플리케이션이 실행될 경로를 지정할 수 있어 경로 문제 회피&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;784&quot; data-start=&quot;705&quot;&gt;
&lt;td data-end=&quot;735&quot; data-start=&quot;705&quot;&gt;  &lt;b&gt;표준 출력/에러 로그 파일 지정 가능&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;784&quot; data-start=&quot;735&quot;&gt;I/O 탭에서 stdout, stderr 파일 지정해 콘솔 로그 저장 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;847&quot; data-start=&quot;785&quot;&gt;
&lt;td data-end=&quot;806&quot; data-start=&quot;785&quot;&gt;  &lt;b&gt;설정이 GUI로 쉬움&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;847&quot; data-start=&quot;806&quot;&gt;GUI 기반이라 직관적으로 설정 가능 (nssm install)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;899&quot; data-start=&quot;848&quot;&gt;
&lt;td data-end=&quot;864&quot; data-start=&quot;848&quot;&gt;  &lt;b&gt;가볍고 무료&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;899&quot; data-start=&quot;864&quot;&gt;설치 없이도 단일 실행 파일로 사용 가능 (Portable)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;904&quot; data-start=&quot;901&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;919&quot; data-start=&quot;906&quot; data-ke-size=&quot;size26&quot;&gt;❌ NSSM의 단점&lt;/h2&gt;
&lt;div&gt;&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;
&lt;div&gt;&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1318&quot; data-start=&quot;921&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1318&quot; data-start=&quot;949&quot;&gt;
&lt;tr data-end=&quot;1012&quot; data-start=&quot;949&quot;&gt;
&lt;td data-end=&quot;969&quot; data-start=&quot;949&quot;&gt;⚠️ &lt;b&gt;정식 유지보수 중단&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1012&quot; data-start=&quot;969&quot;&gt;공식적으로는 개발이 중단되었고, NSSM 2.24가 마지막 릴리즈입니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1076&quot; data-start=&quot;1013&quot;&gt;
&lt;td data-end=&quot;1041&quot; data-start=&quot;1013&quot;&gt;  &lt;b&gt;에러 로그는 기본적으로 콘솔 출력&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1076&quot; data-start=&quot;1041&quot;&gt;별도로 파일 로그 설정하지 않으면 문제 원인 파악 어려움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1142&quot; data-start=&quot;1077&quot;&gt;
&lt;td data-end=&quot;1108&quot; data-start=&quot;1077&quot;&gt;  &lt;b&gt;서비스 설정 변경 시 수동 재등록 필요&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1142&quot; data-start=&quot;1108&quot;&gt;설정 변경이 즉시 반영되지 않고 재시작 필요할 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1219&quot; data-start=&quot;1143&quot;&gt;
&lt;td data-end=&quot;1171&quot; data-start=&quot;1143&quot;&gt;❌ &lt;b&gt;GUI 외에 설정 자동화가 번거로움&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1219&quot; data-start=&quot;1171&quot;&gt;GUI는 편리하지만 대규모 자동화에는 CLI 또는 PowerShell이 더 적합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1318&quot; data-start=&quot;1220&quot;&gt;
&lt;td data-end=&quot;1245&quot; data-start=&quot;1220&quot;&gt;  &lt;b&gt;복잡한 애플리케이션에는 한계&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1318&quot; data-start=&quot;1245&quot;&gt;복잡한 Dependency가 있는 경우엔 sc.exe 또는 WinSW, nssm + bat 조합이 필요할 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1323&quot; data-start=&quot;1320&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1344&quot; data-start=&quot;1325&quot; data-ke-size=&quot;size26&quot;&gt;  NSSM이 적합한 케이스&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1547&quot; data-start=&quot;1346&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1403&quot; data-start=&quot;1346&quot;&gt;Java JAR(Spring Boot 등)을 &lt;b&gt;윈도우에서 백그라운드 서비스&lt;/b&gt;로 실행하고 싶을 때&lt;/li&gt;
&lt;li data-end=&quot;1451&quot; data-start=&quot;1404&quot;&gt;.exe 또는 .bat 파일을 &lt;b&gt;부팅 시 자동으로 실행하고 싶은 경우&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1506&quot; data-start=&quot;1452&quot;&gt;Docker/VM 없이 Windows 서버에서 &lt;b&gt;간단하게 WAS 구동 자동화&lt;/b&gt;하고 싶을 때&lt;/li&gt;
&lt;li data-end=&quot;1547&quot; data-start=&quot;1507&quot;&gt;사내 시스템에서 &lt;b&gt;매우 간단한 백엔드 서비스 자동화&lt;/b&gt;가 필요할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1552&quot; data-start=&quot;1549&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1566&quot; data-start=&quot;1554&quot; data-ke-size=&quot;size26&quot;&gt;  요약&lt;/h2&gt;
&lt;blockquote data-end=&quot;1701&quot; data-start=&quot;1568&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1701&quot; data-start=&quot;1570&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;작지만 강력한 윈도우 서비스 매니저&quot;가 필요하다면 NSSM은 최고의 선택 중 하나로&lt;/b&gt;&lt;br /&gt;다만, 장기적으로는 WinSW, PowerShell 서비스 등록 스크립트, 또는 NSSM 대체 오픈소스들도 고려해볼 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ref&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://nssm.cc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nssm.cc/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1745459181206&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;NSSM - the Non-Sucking Service Manager&quot; data-og-description=&quot;NSSM - the Non-Sucking Service Manager nssm is a service helper which doesn't suck. srvany and other service helper programs suck because they don't handle failure of the application running as a service. If you use such a program you may see a service lis&quot; data-og-host=&quot;nssm.cc&quot; data-og-source-url=&quot;https://nssm.cc/&quot; data-og-url=&quot;https://nssm.cc/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://nssm.cc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nssm.cc/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;NSSM - the Non-Sucking Service Manager&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;NSSM - the Non-Sucking Service Manager nssm is a service helper which doesn't suck. srvany and other service helper programs suck because they don't handle failure of the application running as a service. If you use such a program you may see a service lis&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nssm.cc&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/DevOps</category>
      <category>jar service</category>
      <category>jar 서비스 등록</category>
      <category>NSSM</category>
      <category>window</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/48</guid>
      <comments>https://djlife.tistory.com/48#entry48comment</comments>
      <pubDate>Thu, 24 Apr 2025 12:11:28 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 도커로 환경을 옮긴 후 셀레니움이 실행이 안되는 오류 해결</title>
      <link>https://djlife.tistory.com/47</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;271&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdWB7b/btsNw7KI9ui/5pc1jsXUAxzhQ3GwQkvXKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdWB7b/btsNw7KI9ui/5pc1jsXUAxzhQ3GwQkvXKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdWB7b/btsNw7KI9ui/5pc1jsXUAxzhQ3GwQkvXKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdWB7b%2FbtsNw7KI9ui%2F5pc1jsXUAxzhQ3GwQkvXKK%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;271&quot; height=&quot;242&quot; data-origin-width=&quot;271&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SessionNotCreatedException:&amp;nbsp;Could&amp;nbsp;not&amp;nbsp;start&amp;nbsp;a&amp;nbsp;new&amp;nbsp;session&amp;nbsp;Possible&amp;nbsp;causes&amp;nbsp;are&amp;nbsp;invalid&amp;nbsp;address&amp;nbsp;of&amp;nbsp;the&amp;nbsp;remote&amp;nbsp;server&amp;nbsp;or&amp;nbsp;browser&amp;nbsp;start-up&amp;nbsp;failure.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;도커는 컨테이너 개념인데&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745457783100&quot; class=&quot;dockerfile&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;FROM eclipse-temurin:17-jdk

# Chrome 설치에 필요한 패키지와 라이브러리 설치
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    wget curl gnupg2 unzip fonts-liberation \
    libglib2.0-0 libnss3 libgconf-2-4 libxi6 libgbm1 libgtk-3-0 libx11-6 x11-utils

# Chrome만 설치 (WebDriverManager가 chromedriver는 Java에서 자동 설치)
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - &amp;amp;&amp;amp; \
    sh -c 'echo &quot;deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main&quot; &amp;gt; /etc/apt/sources.list.d/google-chrome.list' &amp;amp;&amp;amp; \
    apt-get update &amp;amp;&amp;amp; \
    apt-get install -y google-chrome-stable &amp;amp;&amp;amp; \
    apt-get clean &amp;amp;&amp;amp; \
    rm -rf /var/lib/apt/lists/*

ENV TZ=Asia/Seoul LANG=ko_KR.UTF-8

# 현재 디렉토리에 있는 jar 복사
COPY credit-*.jar /app.jar

ENTRYPOINT [&quot;java&quot;, &quot;-jar&quot;, &quot;/app.jar&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Trouble Shooting</category>
      <category>chrome</category>
      <category>docker</category>
      <category>Google</category>
      <category>Selenium</category>
      <category>SessionNotCreatedException</category>
      <category>셀레니움</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/47</guid>
      <comments>https://djlife.tistory.com/47#entry47comment</comments>
      <pubDate>Thu, 24 Apr 2025 10:23:39 +0900</pubDate>
    </item>
    <item>
      <title>[SpringBoot] When allowCredentials is true, allowedOrigins cannot contain the special value &amp;quot;*&amp;quot; since that cannot be set on the &amp;quot;Access-Control-Allow-Origin&amp;quot; response header. To allow credentials to a set of origins... 어쩌고저쩌고.. 오류 해결하기  </title>
      <link>https://djlife.tistory.com/46</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhzGbl/btsNrjyS2mV/SMXfQEngFkvY9c7bIvK9OK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhzGbl/btsNrjyS2mV/SMXfQEngFkvY9c7bIvK9OK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhzGbl/btsNrjyS2mV/SMXfQEngFkvY9c7bIvK9OK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhzGbl%2FbtsNrjyS2mV%2FSMXfQEngFkvY9c7bIvK9OK%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;668&quot; height=&quot;327&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1744859104455&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value &quot;*&quot; since that cannot be set on the &quot;Access-Control-Allow-Origin&quot; response header. To allow credentials to a set of origins, list them explicitly or consider using &quot;allowedOriginPatterns&quot; instead.&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;&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;간단한 플레시게임을 만드려고 했는데&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;br /&gt;모든 &lt;b&gt;Access-Control-Allow-Origin * 설정했는데??&lt;/b&gt;&lt;br /&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;&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;pre id=&quot;code_1744860031098&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.car.ndj.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry
                .addMapping(&quot;/**&quot;)
                .allowedOriginPatterns(&quot;*&quot;)
                .allowedMethods(&quot;GET&quot;,&quot;POST&quot;,&quot;PUT&quot;,&quot;DELETE&quot;,&quot;OPTIONS&quot;)
                .allowedHeaders(&quot;*&quot;)
                .allowCredentials(true);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744859200605&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.car.ndj.config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint(&quot;/ws&quot;).setAllowedOriginPatterns(&quot;*&quot;).withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker(&quot;/topic&quot;); // 구독 prefix
        config.setApplicationDestinationPrefixes(&quot;/app&quot;); // 송신 prefix
    }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744859958787&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; setAllowedOrigins -&amp;gt; setAllowedOriginPatterns&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&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;br /&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f8f9fa; color: #1f1f1f; text-align: left;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;allowCredentials가 true인 경우, allowedOrigins는 &quot;Access-Control-Allow-Origin&quot; 응답 헤더에 설정할 수 없는 특수 값 &quot;*&quot;를 포함할 수 없습니다.&lt;/span&gt; 특정 출처 집합에 대한 자격 증명을 허용하려면 해당 출처 집합을 명시적으로 나열하거나 &quot;allowedOriginPatterns&quot;를 사용하는 것이 좋습니다&lt;/span&gt; &lt;/b&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;allowedOrigin(&quot;*&quot;) 과 allowCredentials(true) 는 동시에 설정할 수 없는데&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;&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;span style=&quot;color: #ffffff;&quot;&gt;java.lang.IllegalArgumentException:&amp;nbsp;When&amp;nbsp;allowCredentials&amp;nbsp;is&amp;nbsp;true,&amp;nbsp;allowedOrigins&amp;nbsp;cannot&amp;nbsp;contain&amp;nbsp;the&amp;nbsp;special&amp;nbsp;value&amp;nbsp;&quot;*&quot;&amp;nbsp;since&amp;nbsp;that&amp;nbsp;cannot&amp;nbsp;be&amp;nbsp;set&amp;nbsp;on&amp;nbsp;the&amp;nbsp;&quot;Access-Control-Allow-Origin&quot;&amp;nbsp;response&amp;nbsp;header.&amp;nbsp;To&amp;nbsp;allow&amp;nbsp;credentials&amp;nbsp;to&amp;nbsp;a&amp;nbsp;set&amp;nbsp;of&amp;nbsp;origins,&amp;nbsp;list&amp;nbsp;them&amp;nbsp;explicitly&amp;nbsp;or&amp;nbsp;consider&amp;nbsp;using&amp;nbsp;&quot;allowedOriginPatterns&quot;&amp;nbsp;instead.&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Trouble Shooting</category>
      <category>cors</category>
      <category>IllegalArgumentException</category>
      <category>setallowedoriginpatterns</category>
      <category>setallowedorigins</category>
      <category>SpringBoot</category>
      <category>WebConfig</category>
      <category>websocket</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/46</guid>
      <comments>https://djlife.tistory.com/46#entry46comment</comments>
      <pubDate>Thu, 17 Apr 2025 12:23:16 +0900</pubDate>
    </item>
    <item>
      <title>단말기 결제 VAN 결제 데이터 동기화 하여 회계 전표 자동 생성 시스템화까지  ...☠️</title>
      <link>https://djlife.tistory.com/45</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1057&quot; data-origin-height=&quot;946&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKceTZ/btsMYeXNATw/vLbanqFAKQu1UiYysmr4x1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKceTZ/btsMYeXNATw/vLbanqFAKQu1UiYysmr4x1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKceTZ/btsMYeXNATw/vLbanqFAKQu1UiYysmr4x1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKceTZ%2FbtsMYeXNATw%2FvLbanqFAKQu1UiYysmr4x1%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;1057&quot; height=&quot;946&quot; data-origin-width=&quot;1057&quot; data-origin-height=&quot;946&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 작업을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;9년&lt;/b&gt;&lt;/span&gt; 가까이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;수기&lt;/b&gt;&lt;/span&gt;로 하고 있었다. (사람이.. DB로 강제로 데이터를 밀어넣고 있었음.. )&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; 할 수 있는지 나에게&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;왜 그동안 시도하지 못했는지 알게 되었다.&lt;/u&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;문제점&lt;/b&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;1. 시스템이 많이 노후화 되었고 유지보수도 제대로 안되고 있는 상황 또 포스 프로그램을 직접적으로는 수정할 수 없는 상황 (관리는 되지 않지만 외주업체가 따로 있는 상태) 이며 POS가 너무 불편하다고 취소나 결제를 VAN결제 단말기로 다이렉트로 운영하고 있는 지점들도 있는 상황..&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;2. VAN 거래내역 데이터를 통해 비교하여야 하는데 API를 제공하고 있지 않음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-1. 취소나 거절 승인건에 대해 판단하기 어려움 / POS를 통하지 않고 취소를 하는 경우가 多&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;3.모 회사 데이터베이스는 다이렉트로 붙을 수 없고 모회사 망안에서만 붙을 수 있음&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;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 외상(후불)일 경우 채권 처리가 되지 않아 일일이 수기로 전표를 입력해야 되는 문제&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: #ee2323;&quot;&gt;5. 시스템이 다 흩어져 있고 관련 문서나 담당자가 존재 하지 않음  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결방안&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 마감 프로세스 도입 / 일 단위로 마감을 하면서 계정 코드 입력 할 수 있는 화면 개발 / 지점별로 마감 현황 화면 개발&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(상당 시간 소비.. 마감 로직 설계 등등..)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 크로미움을 이용하여 VAN 사 관리자 페이지에서 일 단위로 데이터 스크래핑 하여 구조에 맞게 결제 데이터 저장&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 자회사 데이터베이스 DB링크를 이용하여 모회사 회계처리 로직 접근 후&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 모회사에 구조에 맞도록 처리&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4. &lt;b&gt;채권 계산하는 로직 개발 -&lt;/b&gt; 데이터 관리 주체가 자회사가 아닌 모회사다 보니 데이터는 읽기만 가능한 상태&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 마감 시 결제 건별로 채권을 재계산 금액 부족 시 선수금 처리 하는 로직 개발&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;5. 노가다 .. 관련된 모든 프로그램 분석 (상당 시간 소비..)&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;노가다성 작업이 많고 파악해야 될 프로그램들이 너무 흩어져있었다.. 관련 담당자들도 없고&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최종&lt;/b&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;효율을 극대화 하기 위해&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 지점이 마감 되면 power automate를 이용하여&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 훅 -&amp;gt; 특정 값 확인 -&amp;gt; 관리자들에게 팀즈 메세지 전송&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;727&quot; data-origin-height=&quot;97&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byFwDV/btsNi8vxmdT/TcAQRwHuk62R2jvg3UObwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byFwDV/btsNi8vxmdT/TcAQRwHuk62R2jvg3UObwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byFwDV/btsNi8vxmdT/TcAQRwHuk62R2jvg3UObwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyFwDV%2FbtsNi8vxmdT%2FTcAQRwHuk62R2jvg3UObwK%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;727&quot; height=&quot;97&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;97&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>변소</category>
      <category>@Scheduled</category>
      <category>Pos</category>
      <category>Van</category>
      <category>결제</category>
      <category>관리 부재</category>
      <category>레거시코드</category>
      <category>스케줄러</category>
      <category>유지보수</category>
      <category>자회사</category>
      <category>포스</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/45</guid>
      <comments>https://djlife.tistory.com/45#entry45comment</comments>
      <pubDate>Thu, 27 Mar 2025 14:44:34 +0900</pubDate>
    </item>
    <item>
      <title>API 동시성 문제 개선하기 (MAX + 1 Key 채번) </title>
      <link>https://djlife.tistory.com/44</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;결제 API&amp;nbsp; 동시성 이슈..&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전자락카 매출정보를 연동하는 API 동시성 문제를 개선해보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업 할 당시에 개발 환경은 jdk 17 , spring boot , mybatis , oracle 이다.&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;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VAN 결제정보 데이터를&amp;nbsp; API를 이용하여 저장하는 단순한 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없는 다이어그램.drawio.png&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;560&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btKq9o/btsL6ANLhQ8/78LN8FqqnZq27XDmKTFlKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btKq9o/btsL6ANLhQ8/78LN8FqqnZq27XDmKTFlKK/img.png&quot; data-alt=&quot;대략 api 흐름..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btKq9o/btsL6ANLhQ8/78LN8FqqnZq27XDmKTFlKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtKq9o%2FbtsL6ANLhQ8%2F78LN8FqqnZq27XDmKTFlKK%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;660&quot; height=&quot;560&quot; data-filename=&quot;제목 없는 다이어그램.drawio.png&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;560&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대략 api 흐름..&lt;/figcaption&gt;
&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;api 응답시간 0.3초&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;/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;/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;/p&gt;
&lt;p 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;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제점 찾기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;예시 코드&lt;/b&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;AS-IS&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737701499256&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity&amp;lt;?&amp;gt; payment(paymentDto dto){
     // ... 코드
        coinLockerMapper.insertA(dto);
        coinLockerMapper.insertB(dto);
        coinLockerMapper.insertC(dto);
        coinLockerMapper.insertD(dto);
        return ResponseEntity.ok(&quot;성공&quot;);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737702754405&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO TABLE_A
        (
        SALE_DATE,
        UPJANG_CODE,
        UPJANG_SEQ,
        SEQ_NO1,
        UPDATE_SYS_DATE,
        UPDATE_EMP_NO,
        UPDATE_IP
        )
        VALUES(
        '영업일자',
        '영업장코드',
        '영업장순번',
        (SELECT NVL(MAX(SEQ_NO1), '0') + 1 FROM TABLE_A
        WHERE jm.UPJANG_CODE ='영업장코드'
        AND jm.UPJANG_SEQ ='업장순번'
        AND jm.SEQ_NO2 = '?'
        AND jm.SALE_DATE = '영업일자'
        AND jm.MENU_CODE = '특정메뉴코드'),
        sysdate,
        '손님',
        'IP'
        )
        ;
        
        ...
        ...
        ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;TO-BE&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737702438823&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity&amp;lt;?&amp;gt; payment(paymentDto dto){
     // ... 코드
        coinLockerMapper.insertABCD(dto);
        return ResponseEntity.ok(&quot;성공&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737704426746&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...

V_SEQ_NO1              NUMBER(4,0) := 1;  
BEGIN
    SELECT (SEQ_NO1 + 1)
    INTO V_SEQ_NO1
    FROM TABILE_SEQ 
    WHERE SALE_DATE = P_SALE_DATE
      AND UPJANG_CODE = P_UPJANG_CODE
      AND TABLE_TYPE = P_TABLE_TYPE
    FOR UPDATE WAIT 3;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      V_SEQ_NO1 := 1;
  END;

INSERT INTO TABLE_A
        (
        SALE_DATE,
        UPJANG_CODE,
        UPJANG_SEQ,
        SEQ_NO1,
        UPDATE_SYS_DATE,
        UPDATE_EMP_NO,
        UPDATE_IP
        )
        VALUES(
        '영업일자',
        '영업장코드',
        '영업장순번',
        V_SEQ_NO1,
        sysdate,
        '손님',
        'IP'
        );


MERGE INTO TABLE_Z target
	  USING (
		  SELECT    '영업일자' AS SALE_DATE, 
		  			'업장코드' AS UPJANG_CODE, 
		  			'테이블타입' AS TABLE_TYPE,
		  			 sysdate AS UPDATE_SYS_DATE,
				     '사용자' AS UPDATE_EMP_NO,
					 '아이디' AS UPDATE_IP 
		FROM DUAL
		  ) source
	  ON (target.SALE_DATE = source.SALE_DATE AND target.UPJANG_CODE = source.UPJANG_CODE AND target.TABLE_TYPE = source.TABLE_TYPE )
	  WHEN MATCHED THEN
	    UPDATE SET SEQ_NO1 = SEQ_NO1 + 1,
	               UPDATE_SYS_DATE = SOURCE.UPDATE_SYS_DATE,
	               UPDATE_EMP_NO = SOURCE.UPDATE_EMP_NO,
	               UPDATE_IP = SOURCE.UPDATE_IP
	        
	  WHEN NOT MATCHED THEN
	    INSERT (SALE_DATE, UPJANG_CODE,UPJANG_SEQ, SEQ_NO1,TABLE_TYPE,UPDATE_SYS_DATE,UPDATE_EMP_NO,UPDATE_IP)
	    VALUES (source.SALE_DATE, source.UPJANG_CODE,'40', 1,source.TABLE_TYPE,SOURCE.UPDATE_SYS_DATE,SOURCE.UPDATE_EMP_NO,SOURCE.UPDATE_IP);&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;&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;문제가 되는 건&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;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;컬럼 조합에 따라 순번을 max +&amp;nbsp; 1을 이용하여 채번&lt;/u&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;이용자수가 적으면 문제가 되지 않지만 급증했을&amp;nbsp;경우에는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;api 처리량이 증가함에 따라&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;&lt;b&gt;unique constraints violation(유일성 제약조건 위배)&lt;/b&gt;&amp;nbsp; 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;해결 방법&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 시퀀스를 이용&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ &lt;b&gt;장점&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;동시성(Concurrency)에 강함&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원자적(Atomic) 연산으로 여러 트랜잭션이 동시에 시퀀스를 요청해도 충돌 없이 동작.&lt;/li&gt;
&lt;li&gt;SELECT SEQ_NAME.NEXTVAL FROM DUAL; 실행 시 별도의 락(Lock) 없이 안전하게 증가.&lt;/li&gt;
&lt;li&gt;대량 삽입(INSERT) 시에도 병목 없이 빠른 키 할당 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빠른 키 생성 (Full Table Scan 없음)&lt;/b&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;채번 테이블을 사용할 경우 발생하는 SELECT MAX(ID) + 1 같은 연산이 필요 없음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Rollback 영향을 받지 않음&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션이 ROLLBACK 되더라도 이미 할당된 시퀀스 값은 그대로 유지됨.&lt;/li&gt;
&lt;li&gt;동일한 값을 두 번 사용하는 일이 없으므로 유니크한 키를 보장.&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;CACHE 옵션을 사용하면 일정 개수의 값을 미리 메모리에 올려두어 DB I/O를 줄이고 성능 향상 가능.&lt;/li&gt;
&lt;li&gt;NOORDER 옵션을 사용하면 RAC 환경에서도 성능을 높일 수 있음.&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;시퀀스를 사용하면 자동으로 증가하는 값(ID) 생성이 가능하여 별도의 로직이 필요 없음.&lt;/li&gt;
&lt;li&gt;UUID나 복합 키보다 간단하게 고유한 값을 생성할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❌ &lt;b&gt;단점&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-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;CACHE 옵션을 사용하면 DB 장애나 재시작 시 미리 할당된 시퀀스 값이 유실될 수 있음.&lt;/li&gt;
&lt;li&gt;트랜잭션 롤백 시에도 이미 할당된 시퀀스 값은 되돌려지지 않음.&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;&lt;span style=&quot;background-color: #9feec3;&quot;&gt;단순 숫자 증가 방식이라 YEAR + DEPT + SEQ 같은 조합 키를 생성할 수 없음.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;특정 그룹(부서별, 연도별)로 별도의 시퀀스를 운영해야 할 경우 관리가 복잡해질 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;초기화(Reset) 어려움&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 조건(예: 연도가 바뀔 때마다 1부터 시작)에서 시퀀스를 초기화하려면 DROP 후 다시 생성해야 함.&lt;/li&gt;
&lt;li&gt;일반적으로 ALTER SEQUENCE로 현재 값을 변경할 수 없으며, 임시 테이블을 활용하는 우회 방법이 필요함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션과 독립적이므로 Rollback 시 순차적 증가가 깨질 수 있음&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, INSERT INTO ... VALUES (SEQ.NEXTVAL) 후 ROLLBACK 하면 해당 값이 유실되며 건너뜀.&lt;/li&gt;
&lt;li&gt;순차적인 숫자가 필요할 경우 시퀀스 대신 채번 테이블을 고려해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일부 데이터베이스(MySQL, SQL Server)에서는 지원되지 않음&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오라클에서는 기본적으로 지원되지만, 다른 DBMS에서는 AUTO_INCREMENT나 채번 테이블을 사용해야 할 수도 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 채번 테이블 만들어서 관리&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ &lt;b&gt;장점&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-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;&lt;span style=&quot;background-color: #9feec3;&quot;&gt;특정 컬럼 조합(예: YEAR + DEPT + SEQ)으로 원하는 방식의 키를 생성할 수 있음.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;단순한 숫자 증가 방식의 시퀀스로는 불가능한 복합 키를 유연하게 생성 가능.&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;특정 조건에 따라 다른 규칙을 적용하여 키 생성 가능.&lt;/li&gt;
&lt;li&gt;예를 들어, 특정 부서(DEPT)별로 연도별(YEAR) 독립적인 증가값 유지 가능.&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;시퀀스는 DB 내부에서 자동 증가하지만, 채번 테이블은 직접 SQL을 통해 제어 가능.&lt;/li&gt;
&lt;li&gt;특정 조건에서 번호를 다시 초기화하는 등의 유연한 관리 가능.&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;시퀀스는 트랜잭션과 독립적으로 동작하므로 Rollback 시 복구 불가능하지만,&lt;br /&gt;채번 테이블은 트랜잭션 롤백 시 다시 원래 값으로 되돌릴 수 있음.&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;일부 데이터베이스(예: MySQL)에서는 시퀀스 기능이 제한적이므로,&lt;br /&gt;채번 테이블을 사용하면 DBMS에 상관없이 일관된 방식으로 키를 관리할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❌ &lt;b&gt;단점&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;동시성 이슈 (Locking 필요)&lt;/b&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;이를 방지하기 위해 SELECT ... FOR UPDATE 또는 LOCK을 사용해야 함.&lt;/li&gt;
&lt;li&gt;성능이 중요한 환경에서는 병목이 될 가능성이 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Full Table Scan 발생 가능&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 조건(YEAR + DEPT)의 최신 키 값을 조회하려면,&lt;br /&gt;인덱스가 적절히 설정되지 않으면 Full Table Scan이 발생할 가능성이 있음.&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;시퀀스는 자동 증가하여 롤백해도 번호가 건너뛰지만,&lt;br /&gt;채번 테이블은 롤백 시 값을 직접 관리해야 일관성 유지 가능.&lt;/li&gt;
&lt;li&gt;예를 들어, 트랜잭션 실패 시 증가된 키를 다시 조정해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;추가적인 I/O 비용 발생&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시퀀스는 메모리에서 관리되지만, 채번 테이블은 매번 DB를 조회해야 함.&lt;/li&gt;
&lt;li&gt;따라서 동시 요청이 많을 경우, 성능 저하 가능성이 있음.&lt;/li&gt;
&lt;li&gt;이를 방지하려면 미리 일정 개수의 키를 캐싱하는 방식 고려 가능.&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;단순한 자동 증가 ID보다 관리할 로직이 많아짐.&lt;/li&gt;
&lt;li&gt;키를 가져오는 별도의 서비스/DAO 로직이 필요하며,&lt;br /&gt;복잡한 비즈니스 로직이 얽힐 가능성이 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&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;✅ &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;컬럼 조합(YEAR + DEPT + SEQ) 기반의 복합 키를 사용해야 할 때&lt;/li&gt;
&lt;li&gt;비즈니스 로직에 따라 키를 다르게 생성해야 할 때&lt;/li&gt;
&lt;li&gt;특정 조건에서 시퀀스를 초기화하거나 재사용해야 할 때&lt;/li&gt;
&lt;li&gt;시퀀스를 지원하지 않는 DB(MySQL 등)에서도 동일한 방식 유지가 필요할 때&lt;/li&gt;
&lt;/ul&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;동시 트랜잭션이 많은 경우 Locking 문제 발생 가능&lt;/li&gt;
&lt;li&gt;채번 테이블 조회 시 추가적인 I/O 부담이 발생하는 것이 문제될 때&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p 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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SELECT ... FOR UPDATE를 사용하여 충돌을 방지하면서 최신 값을 가져오기&lt;/li&gt;
&lt;li&gt;일정 개수(BATCH_SIZE)를 미리 캐싱하여 DB I/O를 줄이기&lt;/li&gt;
&lt;li&gt;인덱스를 잘 설계하여 Full Table Scan 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Trouble Shooting</category>
      <category>API</category>
      <category>api 동시성</category>
      <category>database lock</category>
      <category>Java</category>
      <category>spring boot</category>
      <category>개발자</category>
      <category>동시성 이슈</category>
      <category>디비 락</category>
      <category>테스트코드</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/44</guid>
      <comments>https://djlife.tistory.com/44#entry44comment</comments>
      <pubDate>Tue, 4 Feb 2025 11:33:00 +0900</pubDate>
    </item>
    <item>
      <title>window 10 enterprise 라이센스 만료 후 일정 사용 시간 지나면 강제 종료 되는 현상 해결 방법</title>
      <link>https://djlife.tistory.com/43</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;159&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WVfNd/btsLnF4h2UB/FkeSM2HL0rJpxDzK6apX71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WVfNd/btsLnF4h2UB/FkeSM2HL0rJpxDzK6apX71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WVfNd/btsLnF4h2UB/FkeSM2HL0rJpxDzK6apX71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWVfNd%2FbtsLnF4h2UB%2FFkeSM2HL0rJpxDzK6apX71%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;460&quot; height=&quot;159&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;159&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사 남는 pc 에 로컬 database를 테스트용으로 사용하고 있는데&lt;br /&gt;라이센스가 만료 되어&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1시간 정도 사용하면 강제적으로 종료되는 것을 확인 하였다. (윈도우 이벤트 뷰어에서 확인 가능)&lt;br /&gt;&lt;br /&gt;window license monitoring service를 일시적으로 중지하여&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;추후 라이센스 구매 전까지는 ..  &lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/sysinternals/downloads/psexec&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learn.microsoft.com/en-us/sysinternals/downloads/psexec&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1734575206357&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;PsExec - Sysinternals&quot; data-og-description=&quot;Execute processes on remote systems.&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/en-us/sysinternals/downloads/psexec&quot; data-og-url=&quot;https://learn.microsoft.com/en-us/sysinternals/downloads/psexec&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/izOQg/hyXOm4QdU7/crtTZB1tEK7qKkjk5qFeQ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/sysinternals/downloads/psexec&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/en-us/sysinternals/downloads/psexec&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/izOQg/hyXOm4QdU7/crtTZB1tEK7qKkjk5qFeQ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;PsExec - Sysinternals&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Execute processes on remote systems.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://digitalitskills.com/how-to-stop-windows-server-auto-shutdown-every-hour-after-license-expire/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://digitalitskills.com/how-to-stop-windows-server-auto-shutdown-every-hour-after-license-expire/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>변소</category>
      <category>Enterprise</category>
      <category>window</category>
      <category>Window 10</category>
      <category>윈도우 라이센스</category>
      <category>일정 시간 강제종료</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/43</guid>
      <comments>https://djlife.tistory.com/43#entry43comment</comments>
      <pubDate>Thu, 19 Dec 2024 13:50:21 +0900</pubDate>
    </item>
    <item>
      <title>newman 을 이용하여 node 서버 부하 테스트 및 pm2 클러스트 모드 사용 / 커넥션 풀 사용하여 부하 예방하기  </title>
      <link>https://djlife.tistory.com/42</link>
      <description>&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;후기&amp;nbsp;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다른 사람이 만든 코드를 유지보수한다는게 정말 쉽지 않은 것 같다..&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또 java/spring boot 가 아닌 node/express 환경이다 보니 정이 더 안붙는...  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;br /&gt;원인&lt;/b&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;&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;/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;1. 포스트맨을 이용하여 예약 api 컬렉션 준비&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. node에 newman 종속성 추가 및 실행코드 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. pm2 모니터링&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;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731289194949&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const newman = require('newman'); // Newman 모듈
const instances = 900; 

const runNewmanInstance = () =&amp;gt; {
    return new Promise((resolve, reject) =&amp;gt; {
        newman.run({
            collection: require('./collection.json'), 
            reporters: 'cli',
        }, (err) =&amp;gt; {
            if (err) reject(err);
            else resolve();
        });
    });
};

Promise.all(Array.from({ length: instances }, runNewmanInstance))
    .then(() =&amp;gt; {
        console.log(`${instances}개의 컬렉션이 동시에 완료되었습니다.`);
    })
    .catch((error) =&amp;gt; {
        console.error('오류 발생:', error);
    });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server.js 수정&lt;/p&gt;
&lt;pre id=&quot;code_1731394889213&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;apps&quot; : [
    	{
            &quot;name&quot; : &quot;서버이름&quot;,
            &quot;script&quot; : &quot;src/server.js&quot;,
            &quot;watch&quot; : [&quot;src&quot;],
            &quot;ignore_watch&quot; : [&quot;temp&quot;],
            &quot;watch_option&quot; : {
            	&quot;followSymlinks&quot; : false
            },
	    &quot;exec_mode&quot; : &quot;cluster&quot;,
            &quot;instances&quot; : &quot;max&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;pre id=&quot;code_1731395001708&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pm2 monit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_blob&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djiuXE/btsKFgLalnX/0DYLyFzB5Oj9ZkggP7fD20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djiuXE/btsKFgLalnX/0DYLyFzB5Oj9ZkggP7fD20/img.png&quot; data-alt=&quot;as is&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djiuXE/btsKFgLalnX/0DYLyFzB5Oj9ZkggP7fD20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjiuXE%2FbtsKFgLalnX%2F0DYLyFzB5Oj9ZkggP7fD20%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;1492&quot; height=&quot;640&quot; data-filename=&quot;edited_edited_blob&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;as is&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;변경 후&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731395096789&quot; class=&quot;gcode&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;pm2 monit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_to-be모니터.png&quot; data-origin-width=&quot;1549&quot; data-origin-height=&quot;595&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8dN3t/btsKF8r5e0d/5QfQJB3MkFZKh6aITiw49k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8dN3t/btsKF8r5e0d/5QfQJB3MkFZKh6aITiw49k/img.png&quot; data-alt=&quot;to be&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8dN3t/btsKF8r5e0d/5QfQJB3MkFZKh6aITiw49k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8dN3t%2FbtsKF8r5e0d%2F5QfQJB3MkFZKh6aITiw49k%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;1549&quot; height=&quot;595&quot; data-filename=&quot;edited_to-be모니터.png&quot; data-origin-width=&quot;1549&quot; data-origin-height=&quot;595&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;to be&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스트 모드를 이용하여 분산 처리 하고 나니 was 부하는 줄일 수 있었으나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에 접근하는 행위가 있는 api는 계속 지연되는 현상이 생기는 것을 확인 .. &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;db를 접근할 때 커넥션을 다이렉트로 맺고 끊는 것을 확인 할 수 있었다..&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;이후 앞전에 설명했던 로드 테스트용 스크립트로 수치를 늘렸을 때 as-is와 to-be 확연한 차이가 나는 것을 확인  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ref.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pm2 docs&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://pm2.keymetrics.io/docs/usage/quick-start/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://pm2.keymetrics.io/docs/usage/quick-start/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731286395124&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;PM2 - Quick Start&quot; data-og-description=&quot;Advanced process manager for production Node.js applications. Load balancer, logs facility, startup script, micro service management, at a glance.&quot; data-og-host=&quot;pm2.keymetrics.io&quot; data-og-source-url=&quot;https://pm2.keymetrics.io/docs/usage/quick-start/&quot; data-og-url=&quot;https://pm2.keymetrics.io/docs/usage/quick-start/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bn1OY3/hyXwlLPPjB/kSRlr49Eem9VTIdWllYKPk/img.png?width=710&amp;amp;height=200&amp;amp;face=0_0_710_200,https://scrap.kakaocdn.net/dn/jN5qh/hyXwhQdGUP/tTLwR6hKShlxiuoqthGKcK/img.png?width=2842&amp;amp;height=1396&amp;amp;face=0_0_2842_1396&quot;&gt;&lt;a href=&quot;https://pm2.keymetrics.io/docs/usage/quick-start/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pm2.keymetrics.io/docs/usage/quick-start/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bn1OY3/hyXwlLPPjB/kSRlr49Eem9VTIdWllYKPk/img.png?width=710&amp;amp;height=200&amp;amp;face=0_0_710_200,https://scrap.kakaocdn.net/dn/jN5qh/hyXwhQdGUP/tTLwR6hKShlxiuoqthGKcK/img.png?width=2842&amp;amp;height=1396&amp;amp;face=0_0_2842_1396');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;PM2 - Quick Start&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Advanced process manager for production Node.js applications. Load balancer, logs facility, startup script, micro service management, at a glance.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pm2.keymetrics.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;postman docs&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://learning.postman.com/docs/getting-started/overview/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learning.postman.com/docs/getting-started/overview/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731293756319&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Get started in Postman | Postman Learning Center&quot; data-og-description=&quot;Postman is a collaboration platform for API development. Postman's features simplify each step of building an API and streamline collaboration so you can create better APIs&amp;mdash;faster.&quot; data-og-host=&quot;learning.postman.com&quot; data-og-source-url=&quot;https://learning.postman.com/docs/getting-started/overview/&quot; data-og-url=&quot;https://learning.postman.com/docs/getting-started/overview/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b7yjkp/hyXwoV8r7B/hPrkhVbD4iuQeK0k2wlJlK/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/BuoxP/hyXwoPn4WN/E7KHl47BzfVzksLr5Ye1v1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://learning.postman.com/docs/getting-started/overview/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learning.postman.com/docs/getting-started/overview/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b7yjkp/hyXwoV8r7B/hPrkhVbD4iuQeK0k2wlJlK/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/BuoxP/hyXwoPn4WN/E7KHl47BzfVzksLr5Ye1v1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Get started in Postman | Postman Learning Center&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Postman is a collaboration platform for API development. Postman's features simplify each step of building an API and streamline collaboration so you can create better APIs&amp;mdash;faster.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learning.postman.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;newman&amp;nbsp; docs&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://learning.postman.com/docs/collections/using-newman-cli/command-line-integration-with-newman/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learning.postman.com/docs/collections/using-newman-cli/command-line-integration-with-newman/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731293788094&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Run and test collections from the command line using Newman CLI | Postman Learning Center&quot; data-og-description=&quot;Postman is a collaboration platform for API development. Postman's features simplify each step of building an API and streamline collaboration so you can create better APIs&amp;mdash;faster.&quot; data-og-host=&quot;learning.postman.com&quot; data-og-source-url=&quot;https://learning.postman.com/docs/collections/using-newman-cli/command-line-integration-with-newman/&quot; data-og-url=&quot;https://learning.postman.com/docs/collections/using-newman-cli/command-line-integration-with-newman/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bVwIlj/hyXwnbCxm3/gikoGZaEjFooGkUvkROdg1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ghE5u/hyXwhbDTly/2WK4SbYpv2nT6ikMRkTztk/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://learning.postman.com/docs/collections/using-newman-cli/command-line-integration-with-newman/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learning.postman.com/docs/collections/using-newman-cli/command-line-integration-with-newman/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bVwIlj/hyXwnbCxm3/gikoGZaEjFooGkUvkROdg1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ghE5u/hyXwhbDTly/2WK4SbYpv2nT6ikMRkTztk/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Run and test collections from the command line using Newman CLI | Postman Learning Center&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Postman is a collaboration platform for API development. Postman's features simplify each step of building an API and streamline collaboration so you can create better APIs&amp;mdash;faster.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learning.postman.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%97%B0%EA%B2%B0_%ED%92%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ko.wikipedia.org/wiki/%EC%97%B0%EA%B2%B0_%ED%92%80&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731393992769&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;연결 풀 - 위키백과, 우리 모두의 백과사전&quot; data-og-description=&quot;위키백과, 우리 모두의 백과사전. 연결 풀[1] 또는 커넥션 풀(connection pool)은 소프트웨어 공학에서 데이터베이스로의 추가 요청이 필요할 때 연결을 재사용할 수 있도록 관리되는 데이터베이스 &quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%97%B0%EA%B2%B0_%ED%92%80&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/%EC%97%B0%EA%B2%B0_%ED%92%80&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%97%B0%EA%B2%B0_%ED%92%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%97%B0%EA%B2%B0_%ED%92%80&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;연결 풀 - 위키백과, 우리 모두의 백과사전&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;위키백과, 우리 모두의 백과사전. 연결 풀[1] 또는 커넥션 풀(connection pool)은 소프트웨어 공학에서 데이터베이스로의 추가 요청이 필요할 때 연결을 재사용할 수 있도록 관리되는 데이터베이스&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/DevOps</category>
      <category>api 부하 테스트</category>
      <category>Connection Pool</category>
      <category>createPool</category>
      <category>newman</category>
      <category>node</category>
      <category>node server monitoring</category>
      <category>pm2</category>
      <category>노드 서버</category>
      <category>노드 서버 모니터링</category>
      <category>커넥션 풀</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/42</guid>
      <comments>https://djlife.tistory.com/42#entry42comment</comments>
      <pubDate>Tue, 12 Nov 2024 16:12:38 +0900</pubDate>
    </item>
    <item>
      <title>[Request processing failed: org.springframework.jdbc.UncategorizedSQLException: Error attempting to get column '컬럼명' from result set.  Cause: java.sql.SQLException: 부적합한 열 유형: getBLOB not implemented for class oracle.jdbc.driver.T4CLongRawAccessor 오류 해결 하</title>
      <link>https://djlife.tistory.com/41</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2024-10-25 142438.png&quot; data-origin-width=&quot;1732&quot; data-origin-height=&quot;177&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FFkIR/btsKkoVRisF/6b7ovLnxjKSJD2wk5Hkemk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FFkIR/btsKkoVRisF/6b7ovLnxjKSJD2wk5Hkemk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FFkIR/btsKkoVRisF/6b7ovLnxjKSJD2wk5Hkemk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFFkIR%2FbtsKkoVRisF%2F6b7ovLnxjKSJD2wk5Hkemk%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;1732&quot; height=&quot;177&quot; data-filename=&quot;화면 캡처 2024-10-25 142438.png&quot; data-origin-width=&quot;1732&quot; data-origin-height=&quot;177&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1730077733968&quot; class=&quot;stylus&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;[Request processing failed: org.mybatis.spring.MyBatisSystemException] with root cause

java.sql.SQLException: 부적합한 열 유형: getBLOB not implemented for class oracle.jdbc.driver.T4CLongRawAccessor
	at oracle.jdbc.driver.GeneratedAccessor.getBLOB(GeneratedAccessor.java:1021) ~[ojdbc8-21.9.0.0.jar:21.9.0.0.0]
	at oracle.jdbc.driver.GeneratedStatement.getBLOB(GeneratedStatement.java:289) ~[ojdbc8-21.9.0.0.jar:21.9.0.0.0]
	at oracle.jdbc.driver.GeneratedScrollableResultSet.getBLOB(GeneratedScrollableResultSet.java:547) ~[ojdbc8-21.9.0.0.jar:21.9.0.0.0]
	at oracle.jdbc.driver.GeneratedScrollableResultSet.getBlob(GeneratedScrollableResultSet.java:136) ~[ojdbc8-21.9.0.0.jar:21.9.0.0.0]
	at oracle.jdbc.driver.GeneratedResultSet.getBlob(GeneratedResultSet.java:585) ~[ojdbc8-21.9.0.0.jar:21.9.0.0.0]
	at com.zaxxer.hikari.pool.HikariProxyResultSet.getBlob(HikariProxyResultSet.java) ~[HikariCP-5.1.0.jar:na]
	at org.apache.ibatis.type.BlobTypeHandler.getNullableResult(BlobTypeHandler.java:39) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.type.BlobTypeHandler.getNullableResult(BlobTypeHandler.java:28) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:86) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.type.UnknownTypeHandler.getNullableResult(UnknownTypeHandler.java:77) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:86) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getPropertyMappingValue(DefaultResultSetHandler.java:530) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyPropertyMappings(DefaultResultSetHandler.java:495) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:418) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:366) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:337) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:310) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:202) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:66) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:80) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:65) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:336) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:158) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:110) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:90) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:154) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:142) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:75) ~[mybatis-3.5.14.jar:3.5.14]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:569) ~[na:na]
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:425) ~[mybatis-spring-3.0.3.jar:3.0.3]
	at jdk.proxy2/jdk.proxy2.$Proxy63.selectOne(Unknown Source) ~[na:na]
	at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:160) ~[mybatis-spring-3.0.3.jar:3.0.3]
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:87) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:141) ~[mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86) ~[mybatis-3.5.14.jar:3.5.14]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;mybatis 이용하여 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;oracle database&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블에 데이터를 조회하는 기능을 개발하는 중에&amp;nbsp;&lt;br /&gt;이미지 파일들이 있는 long row 컬럼이 있었는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순하게 resultMap을 사용하여&amp;nbsp;&lt;br /&gt;jdbcType을 &lt;b&gt;LONGVARBINARY&amp;nbsp;&lt;/b&gt;로 선언하면 처리가 가능할 줄 알았으나&amp;nbsp;&lt;br /&gt;jdbcType은insert나 update 같은 쿼리를 수행할 때는 MyBatis가 파라미터 타입을 명확히 인식할 수 있도록 jdbcType을 지정하는 경우 사용하는 것이니 나처럼 바보같은 실수는 하지 않길 바란다..  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #ffffff; color: #333333; text-align: start; border-collapse: collapse; width: 113.023%; height: 377px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 8.01599%; height: 20px; text-align: center;&quot; colspan=&quot;2&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 91.9767%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 80px;&quot;&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: revert; width: 8.01599%; height: 80px;&quot; colspan=&quot;2&quot;&gt;property&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: revert; width: 91.9767%; height: 80px;&quot;&gt;결과 칼럼에 매핑하기 위한 필드나 프로퍼티. 자바빈 프로퍼티가 해당 이름과 일치한다면 그 프로퍼티가 사용될 것이다. 반면에 마이바티스는 해당 이름이 필드를 찾을 것이다. 점 표기를 사용하여 복잡한 프로퍼티 검색을 사용할 수 있다. 예를들어 &amp;ldquo;username&amp;rdquo;과 같이 간단하게 매핑될 수 있거나 &amp;ldquo;address.street.number&amp;rdquo; 처럼 복잡하게 매핑될수도 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;text-align: revert; width: 8.01599%; height: 34px;&quot; colspan=&quot;2&quot;&gt;column&lt;/td&gt;
&lt;td style=&quot;text-align: revert; width: 91.9767%; height: 34px;&quot;&gt;데이터베이스의 칼럼명이나 별칭된 칼럼 라벨. resultSet.getString(columnName) 에 전달되는 같은 문자열이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: revert; width: 8.01599%; height: 40px;&quot; colspan=&quot;2&quot;&gt;javaType&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: revert; width: 91.9767%; height: 40px;&quot;&gt;패키지 경로를 포함한 클래스 전체명이거나 타입 별칭. 자바빈을 사용한다면 마이바티스는 타입을 찾아낼 수 있다. 반면에 HashMap으로 매핑한다면 기대하는 처리를 명확히 하기 위해 javaType 을 명시해야 한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 60px;&quot;&gt;
&lt;td style=&quot;text-align: revert; width: 8.01599%; height: 60px;&quot; colspan=&quot;2&quot;&gt;jdbcType&lt;/td&gt;
&lt;td style=&quot;text-align: revert; width: 91.9767%; height: 60px;&quot;&gt;지원되는 타입 목록에서 설명하는 JDBC 타입. JDBC타입은 insert, update 또는 delete 하는 null 입력이 가능한 칼럼에서만 필요하다. JDBC의 요구사항이지 마이바티스의 요구사항이 아니다. JDBC로 직접 코딩을 하다보면 null이 가능한 값에 이 타입을 지정할 필요가 있을 것이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 52px;&quot;&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: revert; width: 8.01599%; height: 52px;&quot; colspan=&quot;2&quot;&gt;typeHandler&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: revert; width: 91.9767%; height: 52px;&quot;&gt;이 문서 앞에서 이미 타입 핸들러에 대해 설명했다. 이 프로퍼티를 사용하면 디폴트 타입 핸들러를 오버라이드 할 수 있다. 이 값은 TypeHandler구현체의 패키지를 포함한 전체 클래스명이나 타입별칭이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그렇다면 long raw에 값을 어떻게 해야 잘 처리 할 수 있을까?&lt;br /&gt;&lt;br /&gt;resultMap에서 아래 세가지 방법으로&amp;nbsp; 처리 할 수 있다.&lt;br /&gt;&lt;br /&gt;1. &lt;b&gt;javaType&lt;/b&gt;을 &lt;b&gt;byte[]&lt;/b&gt; 로 받는 방법&lt;br /&gt;2. &lt;b&gt;javaType&lt;/b&gt;을 &lt;b&gt;String&lt;/b&gt;으로 받는 방법&lt;br /&gt;3. &lt;b&gt;typeHandler&lt;/b&gt;를 사용하는 방법&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 로직을 한 곳에 집중 시키는 것을 좋아해서 3번을 추천한다.&lt;br /&gt;&lt;br /&gt;그렇다면 &lt;b&gt;typeHandler&amp;nbsp;&lt;/b&gt;는 어떻게 코드를 작성해야 할까?&lt;br /&gt;아래는 long raw 값을 자바에서 받기 위한 typehandler 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1730078048311&quot; class=&quot;groovy&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;package com.xxx.xxx.handler;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class LongRawHandler implements TypeHandler&amp;lt;byte[]&amp;gt; {

    @Override
    public void setParameter(PreparedStatement ps, int i, byte[] parameter, JdbcType jdbcType) throws SQLException {
        if (parameter != null) {
            ps.setBytes(i, parameter);
        } else {
            ps.setNull(i, java.sql.Types.LONGVARBINARY);
        }
    }

    @Override
    public byte[] getResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getBytes(columnName);
    }

    @Override
    public byte[] getResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getBytes(columnIndex);
    }

    @Override
    public byte[] getResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getBytes(columnIndex);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&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;해당 오류 덕분에 mybatis에 대해 더 자세히 알게 된 것 같다 :)&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;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Ref.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/31771198/message-invalid-column-type-getblob-not-implemented-for-class-oracle-jdbc-drive&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackoverflow.com/questions/31771198/message-invalid-column-type-getblob-not-implemented-for-class-oracle-jdbc-drive&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729838788467&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Message Invalid column type: getBLOB not implemented for class oracle.jdbc.driver.T4CLongRawAccessor&quot; data-og-description=&quot;I have a problem when trying to read blob from Oracle DB by using this rs.getBlob(&amp;quot;ARCHIVE_REQ_FILE_BLOB&amp;quot;) I also tried this oracle.sql.BLOB blob= (oracle.sql.BLOB) ((OracleResultSet) rs).&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/31771198/message-invalid-column-type-getblob-not-implemented-for-class-oracle-jdbc-drive&quot; data-og-url=&quot;https://stackoverflow.com/questions/31771198/message-invalid-column-type-getblob-not-implemented-for-class-oracle-jdbc-drive&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bk3v0I/hyXlUIBoxJ/8YsBrh4DDwtVZxfwLAkde1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/31771198/message-invalid-column-type-getblob-not-implemented-for-class-oracle-jdbc-drive&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/31771198/message-invalid-column-type-getblob-not-implemented-for-class-oracle-jdbc-drive&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bk3v0I/hyXlUIBoxJ/8YsBrh4DDwtVZxfwLAkde1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Message Invalid column type: getBLOB not implemented for class oracle.jdbc.driver.T4CLongRawAccessor&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I have a problem when trying to read blob from Oracle DB by using this rs.getBlob(&quot;ARCHIVE_REQ_FILE_BLOB&quot;) I also tried this oracle.sql.BLOB blob= (oracle.sql.BLOB) ((OracleResultSet) rs).&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://mybatis.org/mybatis-3/ko/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mybatis.org/mybatis-3/ko/index.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730074237274&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;mybatis &amp;ndash; 마이바티스 3 | 소개&quot; data-og-description=&quot;마이바티스는 무엇인가? 마이바티스는 개발자가 지정한 SQL, 저장프로시저 그리고 몇가지 고급 매핑을 지원하는 퍼시스턴스 프레임워크이다. 마이바티스는 JDBC로 처리하는 상당부분의 코드와 &quot; data-og-host=&quot;mybatis.org&quot; data-og-source-url=&quot;https://mybatis.org/mybatis-3/ko/index.html&quot; data-og-url=&quot;https://mybatis.org/mybatis-3/ko/index.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://mybatis.org/mybatis-3/ko/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mybatis.org/mybatis-3/ko/index.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;mybatis &amp;ndash; 마이바티스 3 | 소개&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;마이바티스는 무엇인가? 마이바티스는 개발자가 지정한 SQL, 저장프로시저 그리고 몇가지 고급 매핑을 지원하는 퍼시스턴스 프레임워크이다. 마이바티스는 JDBC로 처리하는 상당부분의 코드와&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mybatis.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://mybatis.org/mybatis-3/ko/sqlmap-xml.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mybatis.org/mybatis-3/ko/sqlmap-xml.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730074806522&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;mybatis &amp;ndash; 마이바티스 3 | 매퍼 XML 파일&quot; data-og-description=&quot;Mapper XML 파일 마이바티스의 가장 큰 장점은 매핑구문이다. 이건 간혹 마법을 부리는 것처럼 보일 수 있다. SQL Map XML 파일은 상대적으로 간단하다. 더군다나 동일한 기능의 JDBC 코드와 비교하면 &quot; data-og-host=&quot;mybatis.org&quot; data-og-source-url=&quot;https://mybatis.org/mybatis-3/ko/sqlmap-xml.html&quot; data-og-url=&quot;https://mybatis.org/mybatis-3/ko/sqlmap-xml.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://mybatis.org/mybatis-3/ko/sqlmap-xml.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mybatis.org/mybatis-3/ko/sqlmap-xml.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;mybatis &amp;ndash; 마이바티스 3 | 매퍼 XML 파일&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Mapper XML 파일 마이바티스의 가장 큰 장점은 매핑구문이다. 이건 간혹 마법을 부리는 것처럼 보일 수 있다. SQL Map XML 파일은 상대적으로 간단하다. 더군다나 동일한 기능의 JDBC 코드와 비교하면&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mybatis.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Trouble Shooting</category>
      <category>Java</category>
      <category>mybatis</category>
      <category>mybatis error</category>
      <category>Oracle</category>
      <category>SQLException</category>
      <category>t4clongrawaccessor</category>
      <category>typehandler</category>
      <category>부적합한 열 유형</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/41</guid>
      <comments>https://djlife.tistory.com/41#entry41comment</comments>
      <pubDate>Mon, 28 Oct 2024 10:32:32 +0900</pubDate>
    </item>
    <item>
      <title>[Oracle] 패키지,프로시저,펑션 에서 특정 문자열 찾기    </title>
      <link>https://djlife.tistory.com/40</link>
      <description>&lt;pre id=&quot;code_1728548253744&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
	T1.OBJECT_ID
	, T1.OBJECT_NAME
	, T1.OBJECT_TYPE
	, T2.TEXT
FROM
	USER_OBJECTS T1
	INNER JOIN USER_SOURCE T2 ON T1.OBJECT_NAME = T2.NAME
WHERE
	T1.OBJECT_TYPE IN ('PROCEDURE', 'FUNCTION','PACKAGE BODY')
	AND T2.TEXT LIKE '%검색 문자열%'&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;특정 프로그램 유지보수 중 데이터가 계속 편집이 되는데 인수인계 문서가 없어서 난감하다  &amp;zwj; &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;
&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;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ref.&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://docs.oracle.com/en/database/oracle/oracle-database/21/refrn/USER_OBJECTS.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/en/database/oracle/oracle-database/21/refrn/USER_OBJECTS.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1728548690134&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Database Reference&quot; data-og-description=&quot;USER_OBJECTS describes all objects owned by the current user. Its columns (except for OWNER), are the same as those in ALL_OBJECTS.&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/21/refrn/USER_OBJECTS.html&quot; data-og-url=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/21/refrn/USER_OBJECTS.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/21/refrn/USER_OBJECTS.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/21/refrn/USER_OBJECTS.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Database Reference&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;USER_OBJECTS describes all objects owned by the current user. Its columns (except for OWNER), are the same as those in ALL_OBJECTS.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://asktom.oracle.com/ords/asktom.search?tag=what-is-user-objects&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://asktom.oracle.com/ords/asktom.search?tag=what-is-user-objects&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1728548673781&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;What is user_objects? - Ask TOM&quot; data-og-description=&quot;Response to followup Joseph Giallombardo, August 01, 2017 - 4:04 pm UTC Ok...so user objects is an internal table ok...let me work on that... thanks.&quot; data-og-host=&quot;asktom.oracle.com&quot; data-og-source-url=&quot;https://asktom.oracle.com/ords/asktom.search?tag=what-is-user-objects&quot; data-og-url=&quot;https://asktom.oracle.com/ords/asktom.search?tag=what-is-user-objects&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ti1iI/hyXhR4vNIq/TgNS8OtyEQd0Y9KVShbr4K/img.jpg?width=200&amp;amp;height=200&amp;amp;face=30_60_140_180,https://scrap.kakaocdn.net/dn/bzqXFS/hyXebQ6INA/7KUblgFF0drHThckpyLkV1/img.jpg?width=200&amp;amp;height=200&amp;amp;face=30_60_140_180&quot;&gt;&lt;a href=&quot;https://asktom.oracle.com/ords/asktom.search?tag=what-is-user-objects&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://asktom.oracle.com/ords/asktom.search?tag=what-is-user-objects&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ti1iI/hyXhR4vNIq/TgNS8OtyEQd0Y9KVShbr4K/img.jpg?width=200&amp;amp;height=200&amp;amp;face=30_60_140_180,https://scrap.kakaocdn.net/dn/bzqXFS/hyXebQ6INA/7KUblgFF0drHThckpyLkV1/img.jpg?width=200&amp;amp;height=200&amp;amp;face=30_60_140_180');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;What is user_objects? - Ask TOM&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Response to followup Joseph Giallombardo, August 01, 2017 - 4:04 pm UTC Ok...so user objects is an internal table ok...let me work on that... thanks.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;asktom.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/DATABASE</category>
      <category>function</category>
      <category>Oracle</category>
      <category>Package</category>
      <category>Procedure</category>
      <category>오라클</category>
      <category>패키지</category>
      <category>펑션</category>
      <category>프로시저</category>
      <category>프로시저에서 특정  문자열 찾기</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/40</guid>
      <comments>https://djlife.tistory.com/40#entry40comment</comments>
      <pubDate>Thu, 10 Oct 2024 17:25:27 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 리플렉션(Reflection) 이란 무엇인가요?</title>
      <link>https://djlife.tistory.com/39</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-08-13 094123.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqb3ia/btsJW17IUwC/KyhwpND0iHaposoU4q7Rdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqb3ia/btsJW17IUwC/KyhwpND0iHaposoU4q7Rdk/img.png&quot; data-alt=&quot;자바 리플렉션 그림으로 표현(출처 : http://jessezhuang.github.io/article/java-reflection-test/)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqb3ia/btsJW17IUwC/KyhwpND0iHaposoU4q7Rdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbqb3ia%2FbtsJW17IUwC%2FKyhwpND0iHaposoU4q7Rdk%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;580&quot; height=&quot;300&quot; data-filename=&quot;스크린샷 2024-08-13 094123.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;자바 리플렉션 그림으로 표현(출처 : http://jessezhuang.github.io/article/java-reflection-test/)&lt;/figcaption&gt;
&lt;/figure&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;&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;k사 기술 면접에서&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;
&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;
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;그래서 ..&amp;nbsp; Java Reflection 이란 무엇인가요?&lt;/b&gt;  &lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;자바 리플렉션은 프로그램이 실행 중일 때 클래스, 메서드, 필드 등을 동적으로 조회하고 조작할 수 있게 해주는 기능&lt;/li&gt;
&lt;li&gt;이를 통해 런타임에 클래스의 구조를 알아내고, 객체의 메서드를 호출하거나 필드의 값을 수정할 수 있다.&lt;/li&gt;
&lt;li&gt;자바에서&amp;nbsp;이미&amp;nbsp;로딩이&amp;nbsp;완료된&amp;nbsp;클래스에서&amp;nbsp;또&amp;nbsp;다른&amp;nbsp;클래스를&amp;nbsp;동적으로&amp;nbsp;로딩&amp;nbsp;(Dynamic&amp;nbsp;Loading)하여&amp;nbsp;생성자(Constructor),&amp;nbsp;멤버&amp;nbsp;필드(Member&amp;nbsp;Variables)&amp;nbsp;그리고&amp;nbsp;멤버&amp;nbsp;메서드&amp;nbsp;(Member&amp;nbsp;Method)&amp;nbsp;등을&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;기법&lt;/li&gt;
&lt;li&gt;&lt;u&gt;구체적인&amp;nbsp;Class&amp;nbsp;Type을&amp;nbsp;알지&amp;nbsp;못하더라도&amp;nbsp;해당&amp;nbsp;Class의&amp;nbsp;method,&amp;nbsp;type,&amp;nbsp;variable들에&amp;nbsp;접근할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;해주는&amp;nbsp;자바&amp;nbsp;API이며,&amp;nbsp;컴파일된&amp;nbsp;바이트&amp;nbsp;코드를&amp;nbsp;통해&amp;nbsp;Runtime에&amp;nbsp;동적으로&amp;nbsp;특정&amp;nbsp;Class의&amp;nbsp;정보를&amp;nbsp;추출할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;프로그래밍&amp;nbsp;기법&lt;/u&gt;&lt;u&gt;&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;리플렉션의 주요 특징  ️&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;동적 클래스 정보 조회&lt;/b&gt;: 객체의 클래스 타입, 메서드, 필드 등의 정보를 런타임에 확인할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체 생성 및 메서드 호출&lt;/b&gt;: 클래스의 인스턴스를 동적으로 생성하고, 메서드를 호출할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;접근 제어 무시&lt;/b&gt;: private이나 protected 접근 제한자를 무시하고 필드나 메서드에 접근할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;리플렉션을 사용하는 이유  &lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;플러그인 시스템&lt;/b&gt;: 특정 클래스나 메서드가 미리 정의되어 있지 않은 애플리케이션에서 확장 기능을 추가할 때 유용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프레임워크 및 라이브러리 개발&lt;/b&gt;: Spring, Hibernate 등 프레임워크는 리플렉션을 활용해 빈 생성, 의존성 주입 등을 동적으로 처리함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유연성&lt;/b&gt;: &lt;u&gt;컴파일 타임에 정의되지 않은&lt;/u&gt; 객체와의 상호작용이 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;리플렉션의 단점&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;성능 저하&lt;/b&gt;: 리플렉션은 일반적인 코드보다 더 많은 자원을 사용하므로 성능이 떨어질 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴파일 시 안전성 부족&lt;/b&gt;: 런타임 오류가 발생할 가능성이 크다.&lt;/li&gt;
&lt;li&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;언제 리플렉션을 사용해야 할까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플렉션은 고급 기능으로, 주로 &lt;b&gt;프레임워크 개발이나 동적 기능이 필요한 상황&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;예제 코드&lt;/b&gt;&lt;/h3&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_1728261887620&quot; class=&quot;reasonml&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;code&amp;gt;
java-reflection-study/
│
├── src/
│   ├── Main.java
│   ├── com/
│   │   └── example/
│   │       ├── examples/
│   │       │   ├── ClassInfoExample.java
│   │       │   ├── FieldAccessExample.java
│   │       │   ├── MethodInvocationExample.java
│   │       └── interfaces/
│   │       │   └── ReflectionExample.java
│   │       ├── utils/
│   │       │   └── ReflectionUtils.java
│   │       ├── MyClass.java
│   │       ├── Person.java
│   │       └── ExampleRunner.java
│
└── README.md
&amp;lt;/code&amp;gt;&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;main.java&lt;/p&gt;
&lt;pre id=&quot;code_1728261816716&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import com.example.ExampleRunner;

/**
 * 프로그램의 진입점으로, ExampleRunner를 사용해 리플렉션 예제를 실행합니다.
 */
public class Main {

    public static void main(String[] args) {
        ExampleRunner exampleRunner = new ExampleRunner();
        exampleRunner.runExamples();
    }
}&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;객체 지향적 설계 하기 위해&amp;nbsp; 공통으로 사용되는 메소드는 인터페이스로 관리&lt;/p&gt;
&lt;pre id=&quot;code_1728261990859&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example.interfaces;

/**
 * 리플렉션 예제를 위한 공통 인터페이스입니다.
 */
public interface ReflectionExample {

    /**
     * 리플렉션 예제를 실행하는 메서드입니다.
     */
    void runExample();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제 실행 클래스&lt;/p&gt;
&lt;pre id=&quot;code_1728262517771&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example;

import com.example.examples.ClassInfoExample;
import com.example.examples.FieldAccessExample;
import com.example.examples.MethodInvocationExample;
import com.example.interfaces.ReflectionExample;

import java.util.ArrayList;
import java.util.List;

/**
 * 다양한 리플렉션 예제를 실행하는 클래스입니다.
 */
public class ExampleRunner {

    private final List&amp;lt;ReflectionExample&amp;gt; examples = new ArrayList&amp;lt;&amp;gt;();

    public ExampleRunner() {
        // 예제를 리스트에 추가
        examples.add(new ClassInfoExample(MyClass.class));
        examples.add(new MethodInvocationExample(new MyClass(), &quot;sayHello&quot;, &quot;Reflection&quot;));
        examples.add(new FieldAccessExample(new Person(&quot;Alice&quot;, 30), &quot;name&quot;, &quot;Bob&quot;));
    }

    /**
     * 모든 리플렉션 예제를 실행합니다.
     */
    public void runExamples() {
        for (ReflectionExample example : examples) {
            example.runExample();
        }
    }
}&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;&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;pre id=&quot;code_1728262281226&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example.examples;

import com.example.interfaces.ReflectionExample;
import com.example.utils.ReflectionUtils;

/**
 * 클래스 정보 출력 예제를 담당하는 클래스입니다.
 */
public class ClassInfoExample implements ReflectionExample {

    private final Class&amp;lt;?&amp;gt; clazz;

    public ClassInfoExample(Class&amp;lt;?&amp;gt; clazz) {
        this.clazz = clazz;
    }

    @Override
    public void runExample() {
        System.out.println(&quot;=== 클래스 정보 출력 예제 ===&quot;);
        ReflectionUtils.printClassInfo(clazz);
        System.out.println();
    }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 예제 코드 repo Ref &lt;a href=&quot;https://github.com/DongJu-Na/java-reflection-study&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/DongJu-Na/java-reflection-study&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Readme 참고해주세요!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ref.&lt;/b&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;자바 리플렉션 예제 연습 샘플 github repo (추가로 들어갈 예제 샘플코드가 있다면 pr을 날려주세요)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/java-reflection-study&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/DongJu-Na/java-reflection-study&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1728007614670&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - DongJu-Na/java-reflection-study: 리플렉션 쉽게 이해하기!&quot; data-og-description=&quot;리플렉션 쉽게 이해하기! Contribute to DongJu-Na/java-reflection-study development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/DongJu-Na/java-reflection-study&quot; data-og-url=&quot;https://github.com/DongJu-Na/java-reflection-study&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bv3vZ6/hyXea4hA7D/CirTFxQZAhDkU2DI3oWX1k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/drzCWN/hyXaJAu5MA/gXFUOTukkcN9ZHBaqWYHz1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/java-reflection-study&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/DongJu-Na/java-reflection-study&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bv3vZ6/hyXea4hA7D/CirTFxQZAhDkU2DI3oWX1k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/drzCWN/hyXaJAu5MA/gXFUOTukkcN9ZHBaqWYHz1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - DongJu-Na/java-reflection-study: 리플렉션 쉽게 이해하기!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;리플렉션 쉽게 이해하기! Contribute to DongJu-Na/java-reflection-study development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=67YdHbPZJn4&quot;&gt;https://www.youtube.com/watch?v=67YdHbPZJn4&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=67YdHbPZJn4&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/MjAIO/hyXawgTUth/gV312mdsygtkUfCtUybKB0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=800_184_1124_282&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;[10분 테코톡] 파랑, 아키의 리플렉션&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/67YdHbPZJn4&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&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;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #191919; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Q-8FC09OSYg&quot;&gt;https://www.youtube.com/watch?v=Q-8FC09OSYg&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=Q-8FC09OSYg&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/cA7x9q/hyXaETvXuG/iYr9fzJrGsQcBRoCysZ8U0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;자바, 리플렉션&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/Q-8FC09OSYg&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>Java</category>
      <category>java 개발자 면접</category>
      <category>java 개발자 면접 예상 질문</category>
      <category>jdk</category>
      <category>reflection</category>
      <category>리플렉션</category>
      <category>면접 예상 질문</category>
      <category>백엔드 개발자 면접</category>
      <category>자바</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/39</guid>
      <comments>https://djlife.tistory.com/39#entry39comment</comments>
      <pubDate>Mon, 7 Oct 2024 09:52:11 +0900</pubDate>
    </item>
    <item>
      <title>[axios] Axios의 사용자 제공 입력의 잘못된 유효성 검사로 인한 CSRF 취약점  CVE-2023-45857</title>
      <link>https://djlife.tistory.com/37</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내 레거시.. 프론트 프로젝트에서 axios 라이브러리를 보던 중&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;라이브러리를 업데이트 해야겠다..  &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;package.json 파일을 확인해보니..&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;&amp;nbsp;&quot;axios&quot;: &quot;^0.27.2&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ref.&lt;/b&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;&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://github.com/axios/axios/issues/6006&quot;&gt;https://github.com/axios/axios/issues/6006&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1725939736138&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;CVE-2023-45857 (CWE-359) XSRF-TOKEN value is disclosed to an unauthorised actor &amp;middot; Issue #6006 &amp;middot; axios/axios&quot; data-og-description=&quot;Describe the bug Hi team, @jasonsaayman and @DigitalBrainJS, The library inserts the X-XSRF-TOKEN header using the secret XSRF-TOKEN cookie value in all requests to any server when the XSRF-TOKEN c...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/axios/axios/issues/6006&quot; data-og-url=&quot;https://github.com/axios/axios/issues/6006&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bGzbM1/hyWZk1ZXDv/e4c81F8H712XKFKfKWjPX0/img.png?width=1200&amp;amp;height=600&amp;amp;face=991_127_1060_202&quot;&gt;&lt;a href=&quot;https://github.com/axios/axios/issues/6006&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/axios/axios/issues/6006&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bGzbM1/hyWZk1ZXDv/e4c81F8H712XKFKfKWjPX0/img.png?width=1200&amp;amp;height=600&amp;amp;face=991_127_1060_202');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CVE-2023-45857 (CWE-359) XSRF-TOKEN value is disclosed to an unauthorised actor &amp;middot; Issue #6006 &amp;middot; axios/axios&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Describe the bug Hi team, @jasonsaayman and @DigitalBrainJS, The library inserts the X-XSRF-TOKEN header using the secret XSRF-TOKEN cookie value in all requests to any server when the XSRF-TOKEN c...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://nvd.nist.gov/vuln/detail/CVE-2023-45857#match-13074642&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nvd.nist.gov/vuln/detail/CVE-2023-45857#match-13074642&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1725939925229&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;NVD - CVE-2023-45857&quot; data-og-description=&quot;References to Advisories, Solutions, and Tools By selecting these links, you will be leaving NIST webspace. We have provided these links to other web sites because they may have information that would be of interest to you. No inferences should be drawn on&quot; data-og-host=&quot;nvd.nist.gov&quot; data-og-source-url=&quot;https://nvd.nist.gov/vuln/detail/CVE-2023-45857#match-13074642&quot; data-og-url=&quot;https://nvd.nist.gov/vuln/detail/CVE-2023-45857#match-13074642&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2023-45857#match-13074642&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nvd.nist.gov/vuln/detail/CVE-2023-45857#match-13074642&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;NVD - CVE-2023-45857&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;References to Advisories, Solutions, and Tools By selecting these links, you will be leaving NIST webspace. We have provided these links to other web sites because they may have information that would be of interest to you. No inferences should be drawn on&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nvd.nist.gov&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://portswigger.net/web-security/csrf/preventing&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://portswigger.net/web-security/csrf/preventing&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1725939736377&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;How to prevent CSRF vulnerabilities | Web Security Academy&quot; data-og-description=&quot;In this section, we'll provide some high-level guidance on how you can protect your own websites from the kinds of vulnerabilities we've demonstrated in our ...&quot; data-og-host=&quot;portswigger.net&quot; data-og-source-url=&quot;https://portswigger.net/web-security/csrf/preventing&quot; data-og-url=&quot;https://portswigger.net/web-security/csrf/preventing&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xKwG6/hyWZaLQ8h4/3hlKCycJOqNyuT90OWPBKk/img.png?width=1201&amp;amp;height=603&amp;amp;face=0_0_1201_603&quot;&gt;&lt;a href=&quot;https://portswigger.net/web-security/csrf/preventing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://portswigger.net/web-security/csrf/preventing&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xKwG6/hyWZaLQ8h4/3hlKCycJOqNyuT90OWPBKk/img.png?width=1201&amp;amp;height=603&amp;amp;face=0_0_1201_603');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;How to prevent CSRF vulnerabilities | Web Security Academy&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;In this section, we'll provide some high-level guidance on how you can protect your own websites from the kinds of vulnerabilities we've demonstrated in our ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;portswigger.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Front-End</category>
      <category>axios</category>
      <category>JSON</category>
      <category>package.json</category>
      <category>React</category>
      <category>VUE</category>
      <category>Web security</category>
      <category>라이브러리</category>
      <category>보안취약점</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/37</guid>
      <comments>https://djlife.tistory.com/37#entry37comment</comments>
      <pubDate>Tue, 10 Sep 2024 12:53:57 +0900</pubDate>
    </item>
    <item>
      <title>uncategorized SQLException; SQL state [99999]; error code [17056]; 지원되지 않는 문자 집합(클래스 경로에 orai18n.jar 추가): KO16KSC5601 에러 해결 방법!  ️</title>
      <link>https://djlife.tistory.com/36</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1432&quot; data-origin-height=&quot;214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5SDTK/btsJkZRzb7W/7WAdhrmfszxOq1AnpuQgJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5SDTK/btsJkZRzb7W/7WAdhrmfszxOq1AnpuQgJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5SDTK/btsJkZRzb7W/7WAdhrmfszxOq1AnpuQgJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5SDTK%2FbtsJkZRzb7W%2F7WAdhrmfszxOq1AnpuQgJ1%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;1432&quot; height=&quot;214&quot; data-origin-width=&quot;1432&quot; data-origin-height=&quot;214&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cause:&amp;nbsp;java.sql.SQLException:&amp;nbsp;지원되지&amp;nbsp;않는&amp;nbsp;문자&amp;nbsp;집합(클래스&amp;nbsp;경로에&amp;nbsp;orai18n.jar&amp;nbsp;추가):&amp;nbsp;KO16KSC5601 &lt;br /&gt;;&amp;nbsp;uncategorized&amp;nbsp;SQLException;&amp;nbsp;SQL&amp;nbsp;state&amp;nbsp;[99999];&amp;nbsp;error&amp;nbsp;code&amp;nbsp;[17056];&amp;nbsp;지원되지&amp;nbsp;않는&amp;nbsp;문자&amp;nbsp;집합(클래스&amp;nbsp;경로에&amp;nbsp;orai18n.jar&amp;nbsp;추가):&amp;nbsp;KO16KSC5601]&amp;nbsp;with&amp;nbsp;root&amp;nbsp;cause&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;&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;gradle&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1725000750214&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// https://mvnrepository.com/artifact/com.oracle.ojdbc/orai18n
implementation group: 'com.oracle.ojdbc', name: 'orai18n', version: '19.3.0.0'&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;maven&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1725000776183&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- https://mvnrepository.com/artifact/com.oracle.ojdbc/orai18n --&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.oracle.ojdbc&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;orai18n&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;19.3.0.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&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;&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;&lt;a href=&quot;https://mvnrepository.com/artifact/com.oracle.ojdbc/orai18n/19.3.0.0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mvnrepository.com/artifact/com.oracle.ojdbc/orai18n/19.3.0.0&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Trouble Shooting</category>
      <category>error</category>
      <category>Java</category>
      <category>KO16KSC5601</category>
      <category>Oracle</category>
      <category>orai18n.jar</category>
      <category>spring</category>
      <category>에러</category>
      <category>오류</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/36</guid>
      <comments>https://djlife.tistory.com/36#entry36comment</comments>
      <pubDate>Fri, 30 Aug 2024 15:53:23 +0900</pubDate>
    </item>
    <item>
      <title>outlook 자격 증명 팝업이 반복해서  나올 경우  </title>
      <link>https://djlife.tistory.com/35</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_화면 캡처 2024-08-23 093810.png&quot; data-origin-width=&quot;1093&quot; data-origin-height=&quot;853&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tAzy8/btsJdllHMuG/kZmc4dgwFIQRj9PI7rXaZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tAzy8/btsJdllHMuG/kZmc4dgwFIQRj9PI7rXaZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tAzy8/btsJdllHMuG/kZmc4dgwFIQRj9PI7rXaZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtAzy8%2FbtsJdllHMuG%2FkZmc4dgwFIQRj9PI7rXaZK%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;1093&quot; height=&quot;853&quot; data-filename=&quot;edited_화면 캡처 2024-08-23 093810.png&quot; data-origin-width=&quot;1093&quot; data-origin-height=&quot;853&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;
&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;차선책으로 아웃룩으로 포워딩 하여 사용하려고 하니&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://answers.microsoft.com/ko-kr/outlook_com/forum/all/%EC%95%84%EC%9B%83%EB%A3%A92013-%EC%B5%9C%EC%B4%88/07b314d9-c9f6-427e-909c-c470a0ab2593&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://answers.microsoft.com/ko-kr/outlook_com/forum/all/%EC%95%84%EC%9B%83%EB%A3%A92013-%EC%B5%9C%EC%B4%88/07b314d9-c9f6-427e-909c-c470a0ab2593&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724376472607&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;리디렉션 중&quot; data-og-description=&quot;&quot; data-og-host=&quot;login.microsoftonline.com&quot; data-og-source-url=&quot;https://answers.microsoft.com/ko-kr/outlook_com/forum/all/%EC%95%84%EC%9B%83%EB%A3%A92013-%EC%B5%9C%EC%B4%88/07b314d9-c9f6-427e-909c-c470a0ab2593&quot; data-og-url=&quot;https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=a81d90ac-aa75-4cf8-b14c-58bf348528fe&amp;amp;redirect_uri=https%3A%2F%2Fanswers.microsoft.com&amp;amp;response_type=code%20id_token&amp;amp;scope=openid%20profile&amp;amp;state=OpenIdConnect.AuthenticationProperties%3DjdTdlNPUIYd0VwmgDZ4FRQ-3-DBd6Xsk3QLIjy85AsbzdC0Em_vd-QjxWZYTJqCzM2WEZDnu5atNgtn_LChPOmiG_q8rxihm7orlvCHwdkSO2Gy8UKzDO7DYUsmCN1keMODzbqBtHPrydaqOJfnR_3pRu5qy_Jm-VqdstJDUtbun7-bpuKCs0IshCsx5CSqVStcYdUQsFB9zOLDKEbFvX7NesAwWF5308NW3WM3QVKFYLocnFcXeAX-3klMCyu8v00x8mYbVtZki6hSHryK-Frra1m9xJmpEi154kC9c7ITjSeUR0kbbVSLgNLIDAzt5C5RmH9A5jcBJNLt0OM1L4G5hp0voAVKTOuEPk9N8nijY_CO4FIKG_-uuSQS91cuX&amp;amp;response_mode=form_post&amp;amp;nonce=638599732726616726.NGQ0NjAzNzYtM2JiMi00YTg4LThlMzQtNjI3NjVlNGUzNGQ5MDYzMjhmOTMtZDYzZC00MDA2LTgxY2UtNjFiM2I4ZWVkZWQ5&amp;amp;nopa=2&amp;amp;prompt=none&amp;amp;x-client-SKU=ID_NET472&amp;amp;x-client-ver=7.6.0.0&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://answers.microsoft.com/ko-kr/outlook_com/forum/all/%EC%95%84%EC%9B%83%EB%A3%A92013-%EC%B5%9C%EC%B4%88/07b314d9-c9f6-427e-909c-c470a0ab2593&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://answers.microsoft.com/ko-kr/outlook_com/forum/all/%EC%95%84%EC%9B%83%EB%A3%A92013-%EC%B5%9C%EC%B4%88/07b314d9-c9f6-427e-909c-c470a0ab2593&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;리디렉션 중&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;login.microsoftonline.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&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;&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>변소</category>
      <category>outlook</category>
      <category>outlook 자격증명</category>
      <category>outlook 자격증명 반복</category>
      <category>아웃룩</category>
      <category>이메일</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/35</guid>
      <comments>https://djlife.tistory.com/35#entry35comment</comments>
      <pubDate>Fri, 23 Aug 2024 10:31:09 +0900</pubDate>
    </item>
    <item>
      <title>[SpringBoot]  스프링을 이용하여 가벼운(간단한) 스케줄링 작업 처리하는 방법  </title>
      <link>https://djlife.tistory.com/34</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3ceacd0c-70c0-4c34-a4b2-1246f7c91ea6.jpg&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btrWk1/btsI2w2nOND/KYf2FesIQeqJInXCLj45Bk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btrWk1/btsI2w2nOND/KYf2FesIQeqJInXCLj45Bk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btrWk1/btsI2w2nOND/KYf2FesIQeqJInXCLj45Bk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtrWk1%2FbtsI2w2nOND%2FKYf2FesIQeqJInXCLj45Bk%2Fimg.jpg&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;602&quot; height=&quot;338&quot; data-filename=&quot;3ceacd0c-70c0-4c34-a4b2-1246f7c91ea6.jpg&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 처리할 양이 상당히 적고 (100 Row 미만) 작업이 복잡하지 않아 스케줄러를 이용하기로 결정  &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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;Spring에서 제공하는 스케줄러로는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #008000; text-align: left;&quot;&gt;Spring Scheduler(종속 추가 x)&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #008000; text-align: left;&quot;&gt;Spring Quartz(종속 추가 필요)&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스프링 스케줄러 사용 방법&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 스케줄링을 활성화 하려면 @EnableScheduling 주석을 메인 Spring Boot 애플리케이션 클래스에 추가하거나 프로젝트에서 만든 구성 클래스에 추가하기만 하면 된다.  &lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1723510634277&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class ApiApplication {

	public static void main(String[] args) {
		SpringApplication.run(ApiApplication.class, args);
	}

}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 스케줄이 활성화 되었다면 @Scheduled&amp;nbsp; 어노테이션을 이용하여 스케줄링 작업할 코드를 작성하면 끝 엄청 간단하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 어노테이션에서는 세가지 설정이 가능하다. 나는&amp;nbsp; cron표현식을 이용했는데 보다 자세한 이용 방법은 아래 참조 링크 확인하길!  &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;fixedDelay&amp;nbsp;:&amp;nbsp;scheduler가&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;fixedRate&amp;nbsp;:&amp;nbsp;scheduler가&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;cron 표현식 : cron = 0? : 앞에서 부터 초, 분, 시, 일, 월, 요일(연도)순으로 진행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723510682324&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import com.elysian.api.domain.temp.service.TempService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Component
@Slf4j
@RequiredArgsConstructor
public class TempTask {

    private final TempService tempService;

    @Value(&quot;${schedule.use}&quot;)
    private boolean useSchedule;

    @Scheduled(cron = &quot;${schedule.cron}&quot;)
    public void mainJob() {
        try {
            if (useSchedule) {
                String formatDate = LocalDateTime.now().minusDays(1).format(DateTimeFormatter.ofPattern(&quot;yyyyMMdd&quot;));
                log.info(&quot;Batch Start Date = {}&quot;,formatDate);
                tempService.sync(formatDate);
            }
        }  catch (Exception e) {
            log.info(&quot;* Batch 시스템이 예기치 않게 종료되었습니다. Message: {}&quot;, e.getMessage());
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 Ref.&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://spring.io/guides/gs/scheduling-tasks&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://spring.io/guides/gs/scheduling-tasks&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723508915795&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Getting Started | Scheduling Tasks&quot; data-og-description=&quot;Although scheduled tasks can be embedded in web applications, the simpler approach (shown in this guide) creates a standalone application. To do so, package everything in a single, executable JAR file, driven by a Java main() method. The following snippet &quot; data-og-host=&quot;spring.io&quot; data-og-source-url=&quot;https://spring.io/guides/gs/scheduling-tasks&quot; data-og-url=&quot;https://spring.io/guides/gs/scheduling-tasks&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/1BleH/hyWOkml5nn/Rxfo6DdCScqgDFUPSMNLN1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/c9P0Am/hyWKCoEwox/Dw4r3Di92fkw75XzLN329K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://spring.io/guides/gs/scheduling-tasks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://spring.io/guides/gs/scheduling-tasks&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/1BleH/hyWOkml5nn/Rxfo6DdCScqgDFUPSMNLN1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/c9P0Am/hyWKCoEwox/Dw4r3Di92fkw75XzLN329K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Getting Started | Scheduling Tasks&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Although scheduled tasks can be embedded in web applications, the simpler approach (shown in this guide) creates a standalone application. To do so, package everything in a single, executable JAR file, driven by a Java main() method. The following snippet&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableScheduling.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableScheduling.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723508940844&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;EnableScheduling (Spring Framework 6.1.11 API)&quot; data-og-description=&quot;Enables Spring's scheduled task execution capability, similar to functionality found in Spring's XML namespace. To be used on @Configuration classes as follows: @Configuration @EnableScheduling public class AppConfig { // various @Bean definitions } This e&quot; data-og-host=&quot;docs.spring.io&quot; data-og-source-url=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableScheduling.html&quot; data-og-url=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableScheduling.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableScheduling.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableScheduling.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;EnableScheduling (Spring Framework 6.1.11 API)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Enables Spring's scheduled task execution capability, similar to functionality found in Spring's XML namespace. To be used on @Configuration classes as follows: @Configuration @EnableScheduling public class AppConfig { // various @Bean definitions } This e&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723508957491&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Scheduled (Spring Framework 6.1.11 API)&quot; data-og-description=&quot;A cron-like expression, extending the usual UN*X definition to include triggers on the second, minute, hour, day of month, month, and day of week.&quot; data-og-host=&quot;docs.spring.io&quot; data-og-source-url=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html&quot; data-og-url=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Scheduled (Spring Framework 6.1.11 API)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A cron-like expression, extending the usual UN*X definition to include triggers on the second, minute, hour, day of month, month, and day of week.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723509079957&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Cron Expressions&quot; data-og-description=&quot;A Cron Expressions Cron expressions are used to configure instances of CronTrigger, a subclass of org.quartz.Trigger. A cron expression is a string consisting of six or seven subexpressions (fields) that describe individual details of the schedule. These f&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm&quot; data-og-url=&quot;https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Cron Expressions&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A Cron Expressions Cron expressions are used to configure instances of CronTrigger, a subclass of org.quartz.Trigger. A cron expression is a string consisting of six or seven subexpressions (fields) that describe individual details of the schedule. These f&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://djlife.tistory.com/31&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://djlife.tistory.com/31&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723510477392&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;스프링 배치(Spring Batch)  시작하기 ! &quot; data-og-description=&quot;스프링 배치 5가 릴리즈된지 거의 1년이 흘렀는데 이 때는 안보고 있다가..   급하게 스케줄러와 배치를 이용해야 되는 일이 생겻다   내가 만들어야 할 프로그램 프로세스 흐름은 이와 같다.&quot; data-og-host=&quot;djlife.tistory.com&quot; data-og-source-url=&quot;https://djlife.tistory.com/31&quot; data-og-url=&quot;https://djlife.tistory.com/31&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/RHFdy/hyWOo96W87/cIiTm5DrUCIOmqSsASk4n1/img.png?width=761&amp;amp;height=315&amp;amp;face=0_0_761_315,https://scrap.kakaocdn.net/dn/bGmzKd/hyWOgYyeBV/XHjo8zBZbRDkRO03A3Y9W1/img.png?width=761&amp;amp;height=315&amp;amp;face=0_0_761_315,https://scrap.kakaocdn.net/dn/bE3lrm/hyWOpgS71s/G0tGjh1NTGpC4sLoLj10K0/img.png?width=2048&amp;amp;height=1443&amp;amp;face=0_0_2048_1443&quot;&gt;&lt;a href=&quot;https://djlife.tistory.com/31&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://djlife.tistory.com/31&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/RHFdy/hyWOo96W87/cIiTm5DrUCIOmqSsASk4n1/img.png?width=761&amp;amp;height=315&amp;amp;face=0_0_761_315,https://scrap.kakaocdn.net/dn/bGmzKd/hyWOgYyeBV/XHjo8zBZbRDkRO03A3Y9W1/img.png?width=761&amp;amp;height=315&amp;amp;face=0_0_761_315,https://scrap.kakaocdn.net/dn/bE3lrm/hyWOpgS71s/G0tGjh1NTGpC4sLoLj10K0/img.png?width=2048&amp;amp;height=1443&amp;amp;face=0_0_2048_1443');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;스프링 배치(Spring Batch) 시작하기 ! &lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;스프링 배치 5가 릴리즈된지 거의 1년이 흘렀는데 이 때는 안보고 있다가..   급하게 스케줄러와 배치를 이용해야 되는 일이 생겻다   내가 만들어야 할 프로그램 프로세스 흐름은 이와 같다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;djlife.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>@EnableScheduling</category>
      <category>@Scheduled</category>
      <category>cron</category>
      <category>fixedDelay</category>
      <category>fixedRate</category>
      <category>spring</category>
      <category>SpringBoot</category>
      <category>스케줄</category>
      <category>스프링배치</category>
      <category>스프링부트</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/34</guid>
      <comments>https://djlife.tistory.com/34#entry34comment</comments>
      <pubDate>Tue, 13 Aug 2024 10:22:48 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 모던 자바(Modern JAVA)  란 무엇인가!!!!  (feat. 새롭게 추가된 기능들)</title>
      <link>https://djlife.tistory.com/33</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1685428169761.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y6fhN/btsF1bHp7dN/gYEwhZGuYTHsvPBoIkRtpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y6fhN/btsF1bHp7dN/gYEwhZGuYTHsvPBoIkRtpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y6fhN/btsF1bHp7dN/gYEwhZGuYTHsvPBoIkRtpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy6fhN%2FbtsF1bHp7dN%2FgYEwhZGuYTHsvPBoIkRtpK%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;1280&quot; height=&quot;720&quot; data-filename=&quot;1685428169761.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ChatGPT_logo.svg.webp&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyGE0I/btsF1Lal6Ky/q0Lw8sK00Sdd1fYD2bNktk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyGE0I/btsF1Lal6Ky/q0Lw8sK00Sdd1fYD2bNktk/img.webp&quot; data-alt=&quot;GPT 3.5&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyGE0I/btsF1Lal6Ky/q0Lw8sK00Sdd1fYD2bNktk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyGE0I%2FbtsF1Lal6Ky%2Fq0Lw8sK00Sdd1fYD2bNktk%2Fimg.webp&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;55&quot; height=&quot;1200&quot; data-filename=&quot;ChatGPT_logo.svg.webp&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GPT 3.5&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;&lt;b&gt;모던 자바(Modern Java)&lt;/b&gt;&quot;는 주로 자바 프로그래밍 언어의 최신 기능과 개선된 패러다임을 지칭합니다. 기존의 자바 버전에서 도입된 기능들과는 달리, &lt;b&gt;자바 8 이후부터의 새로운 기능과 변경된 프로그래밍 스타일&lt;/b&gt;을 포함합니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모던 자바에서는 함수형 프로그래밍의 개념을 도입하고, 람다 표현식과 스트림 API 등을 통해 코드를 더욱 간결하고 유연하게 작성할 수 있습니다. 또한, 형식 추론(var 키워드), 모듈 시스템, 레코드(Records) 등과 같은 새로운 기능들이 추가되어 프로그래머가 코드를 작성하고 유지보수하는 데 도움이 됩니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 모던 자바는 자바 언어를 사용하여 최신의 개발 트렌드와 요구 사항에 부합하는 현대적이고 효율적인 코드를 작성하는 것을 의미합니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바8 이후에 새로운 기능들을 활용하여 개발하는 개념을 모던 자바라고 이해하면 될 것 같다.  &lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDK 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;&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;var 키워드의 확장(JDK 10 이상) - &lt;/b&gt;&amp;nbsp;자바 10부터는 var 키워드가 지역 변수 뿐만 아니라 반복 변수 및 익명 클래스의 파라미터로도 사용 가능하고 이는 코드의 가독성을 향상시키고, 반복 변수와 익명 클래스의 형식을 더 명확하게 표현할 수 있게 된다.  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(* &lt;b&gt;Type Inference&lt;/b&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;단 var 타입을 사용하기 전에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오라클에서 var를 출시하게 된 이유와 사용하였을 때 기대효과 단점 등등 꼭 읽어보고 사용하도록 하자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711210881869&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.ndj;

import java.util.Arrays;

public class LocalVariableTypeInference {
    public static void main(String[] args)  {
        // old Java
        String oldName = &quot;DONGJU&quot;;
        int[] oldNums = new int[]{1,2,3,4,5};

        // modern Java
        var newName = &quot;DONGJU&quot;;
        var nums = new int[]{1,2,3,4,5};


        System.out.println(&quot;oldName &amp;gt; &quot; + oldName + &quot; Class  &amp;gt; &quot; + oldName.getClass());
        System.out.println(&quot;oldNums &amp;gt; &quot; + Arrays.toString(oldNums) + &quot; Class  &amp;gt; &quot; + oldNums.getClass());
        System.out.println(&quot;newName &amp;gt; &quot; + newName + &quot; Class  &amp;gt; &quot; + newName.getClass());
        System.out.println(&quot;nums &amp;gt; &quot; + Arrays.toString(nums) + &quot; Class  &amp;gt; &quot; + nums.getClass());

    }
}&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;&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;스위치&amp;nbsp;표현식&amp;nbsp;(Switch&amp;nbsp;Expressions)&amp;nbsp;-&lt;/b&gt;&amp;nbsp; 자바 12부터는 스위치 표현식이 개선되어서 더 간결하고 가독성 있는 코드를 작성할 수 있다.  아래 코드를 보고 표현식 사용 유무 차이를 확인해보자!  &lt;/p&gt;
&lt;pre id=&quot;code_1711213778181&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.ndj;

public class SwitchNewStatement {

    public static void main(String[] args) {

        // old way
        int olcDayNum = 6;
        String oldDay = &quot;&quot;;

        switch(olcDayNum) {
            case 1:
                oldDay = &quot;Monday&quot;;
                break;
            case 2:
                oldDay = &quot;Tuesday&quot;;
                break;
            case 3:
                oldDay = &quot;Wednesday&quot;;
                break;
            case 4:
                oldDay = &quot;Thursday&quot;;
                break;
            case 5:
                oldDay = &quot;Friday&quot;;
                break;
            case 6:
                oldDay = &quot;Saturday&quot;;
                break;
            case 7:
                oldDay = &quot;Sunday&quot;;
                break;
            default:
                oldDay = &quot;Not Valid&quot;;
                break;
        }

        // new way
        int newDayNum = 6;
        String newDay = switch (newDayNum) {
            case 1 -&amp;gt; &quot;Monday&quot;;
            case 2 -&amp;gt; &quot;Tuesday&quot;;
            case 3 -&amp;gt; &quot;Wednesday&quot;;
            case 4 -&amp;gt; &quot;Thursday&quot;;
            case 5 -&amp;gt; &quot;Friday&quot;;
            case 6 -&amp;gt; &quot;Saturday&quot;;
            case 7 -&amp;gt; &quot;Sunday&quot;;
            default -&amp;gt; &quot;Not Valid&quot;;
        };
        
        System.out.println(&quot;oldDay &amp;gt; &quot; + oldDay);
        System.out.println(&quot;newDay &amp;gt; &quot; + newDay);


    }

}&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;&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;span style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot;&gt;&lt;b&gt;텍스트 블록(Text Block) -&lt;/b&gt;&amp;nbsp; 기능이 자바 15에 정식으로 추가 되었다. 기능 추가가 아닌 언어적인 변화로 자바에서 XML, SQL 등 멀티라인으로 문자열을 사용하는 개발자들에게 희소식이다.  &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 style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot;&gt;아래 코드를 보면&amp;nbsp; &lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot;&gt;이스케이프 시퀀스 와 (+) 연산자를 사용하지 않아 코드가 훨씬 깔끔한걸 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711215119117&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.ndj;

public class TextBlock {

    public static void main(String[] args) {
        // old way
        String oldMultiLineString = &quot;&amp;lt;header&amp;gt;\n&quot; +
                &quot;\t&amp;lt;h1&amp;gt;Welcome DJ&amp;lt;/h1&amp;gt;\n&quot; +
                &quot;&amp;lt;/header&amp;gt;&quot;;

        // new way
        String newMultiLineString = &quot;&quot;&quot;
                &amp;lt;header&amp;gt;
                    &amp;lt;h1&amp;gt;Welcome DJ&amp;lt;/h1&amp;gt;
                &amp;lt;/header&amp;gt;
            &quot;&quot;&quot;;

        System.out.println(oldMultiLineString);
        System.out.println(newMultiLineString);

    }

}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Records (레코드) -&amp;nbsp;&lt;/b&gt; 자바 14부터는 레코드(record)라는 새로운 데이터 타입이 도입되었는데, 레코드 타입은 불변성(immutability)과 데이터 전달 객체(data transfer object)를 지원하는 간결한 방식으로 데이터를 표현할 수 있도록 한다.&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;nbsp; 읽어보면 좋을만한 글&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.baeldung.com/java-record-keyword&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.baeldung.com/java-record-keyword&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;DTO 클래스 생성 시 불필요하게 코드 생성 하는것을 줄일 수 있는 정도로 나는 이해하고 있다.  &lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;각 데이터 조각에 대한&lt;span&gt;&amp;nbsp;&lt;/span&gt;private&lt;span&gt;&amp;nbsp;&lt;/span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;final 필드&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;각 필드에 대한 getter&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;각 필드에 해당 인수가 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;공개 생성자&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;모든 필드가 일치할 때 동일한 클래스의 객체에 대해&lt;span&gt;&amp;nbsp;&lt;/span&gt;true를 반환하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;equals&lt;span&gt;&amp;nbsp;&lt;/span&gt;메서드&amp;nbsp;&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;모든 필드가 일치할 때 동일한 값을 반환하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;hashCode 메서드&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;클래스 이름, 각 필드 이름 및 해당 값을 포함하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;toString 메소드&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711216059868&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.ndj;

public class RecordClass {
    // old way MemberDto 클래스를 외부 클래스로 변경
    public static class MemberDto {
        private String name;
        private int age;

        public MemberDto(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }

        public void setName(String name) {
            this.name = name;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return &quot;MemberDto{&quot; +
                    &quot;name='&quot; + name + '\'' +
                    &quot;, age=&quot; + age +
                    '}';
        }

    }

    // new way Record 클래스 선언
    record Member(String name, int age) {}

    public static void main(String[] args) {
        MemberDto oldMember = new MemberDto(&quot;DJ&quot;,30);
        System.out.println(oldMember.toString());
        System.out.println(&quot;name &amp;gt; &quot; + oldMember.name);
        System.out.println(&quot;age &amp;gt; &quot; + oldMember.age);

        Member member = new Member(&quot;DJ&quot;,30);
        System.out.println(member.toString());
        System.out.println(&quot;name &amp;gt; &quot; + member.name);
        System.out.println(&quot;age &amp;gt; &quot; + member.age);

    }

}&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;&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;Stream API (스트림 API)&lt;/b&gt; -&amp;nbsp; 자바 8 부터 컬렉션을 처리하고 변환하는 기능을 제공하는데 이를 통해 데이터 처리 과정을 선언적으로 표현할 수 있어 코드의 가독성과 유지보수성을 향상시킨다  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Java 8 스트림 API의 특징을 다음처럼 요약할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;선언형&lt;/b&gt;&amp;nbsp;: 가독성 +&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;코드 조립&lt;/b&gt; : 유연성 +&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;병렬화&lt;/b&gt;&amp;nbsp;: 성능 +&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1711217356669&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.ndj;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamApi {

    public static void main(String[] args) {

        List&amp;lt;String&amp;gt; names = Arrays.asList(&quot;John&quot;, &quot;Doe&quot;, &quot;Jane&quot;, &quot;Alex&quot;, &quot;Alice&quot;);
        List&amp;lt;Integer&amp;gt; numbers = Arrays.asList(1, 2, 3, 4, 5);

        /*******************************************************************
         * old way
         ********************************************************************/

        //Filtering - 데이터 컬렉션에서 특정 조건을 만족하는 요소들만 선택
        List&amp;lt;String&amp;gt; oldFilteredNames = new ArrayList&amp;lt;&amp;gt;();
        for (String name : names) {
            if (name.startsWith(&quot;J&quot;)) {
                oldFilteredNames.add(name);
            }
        }

        System.out.println(oldFilteredNames);

        //Mapping - 데이터 컬렉션의 요소를 다른 형태로 변환
        List&amp;lt;Integer&amp;gt; oldNameLengths = new ArrayList&amp;lt;&amp;gt;();
        for (String name : names) {
            oldNameLengths.add(name.length());
        }

        System.out.println(oldNameLengths);

        //Sorting - 데이터 컬렉션의 요소를 정렬
        List&amp;lt;String&amp;gt; oldSortedNames = new ArrayList&amp;lt;&amp;gt;(names);
        oldSortedNames.sort(Comparator.naturalOrder());

        System.out.println(oldSortedNames);

        //Grouping - 데이터 컬렉션의 요소를 특정 기준으로 그룹화
        Map&amp;lt;Integer, List&amp;lt;String&amp;gt;&amp;gt; oldNamesByLength = new HashMap&amp;lt;&amp;gt;();
        for (String name : names) {
            int length = name.length();
            List&amp;lt;String&amp;gt; group = oldNamesByLength.getOrDefault(length, new ArrayList&amp;lt;&amp;gt;());
            group.add(name);
            oldNamesByLength.put(length, group);
        }

        System.out.println(oldNamesByLength);

        //Reducing - 데이터 컬렉션의 모든 요소를 하나로
        int oldSum = 0;
        for (int num : numbers) {
            oldSum += num;
        }

        System.out.println(oldSum);

        //Processing - 데이터 컬렉션을 병렬로 처리
        int oldSumValue = 0;
        for (int num : numbers) {
            oldSumValue += num;
        }

        System.out.println(oldSumValue);

        //Stream Concatenation - 두 개의 스트림을 연결
        List&amp;lt;String&amp;gt; oldConcatenatedList = new ArrayList&amp;lt;&amp;gt;();
        List&amp;lt;String&amp;gt; oldFirstNames = Arrays.asList(&quot;John&quot;, &quot;Doe&quot;);
        List&amp;lt;String&amp;gt; oldLastNames = Arrays.asList(&quot;Smith&quot;, &quot;Johnson&quot;);
        oldConcatenatedList.addAll(oldFirstNames);
        oldConcatenatedList.addAll(oldLastNames);
        System.out.println(oldConcatenatedList);


        /*******************************************************************
         * new way Stream API Use
         ********************************************************************/

        //Filtering - 데이터 컬렉션에서 특정 조건을 만족하는 요소들만 선택
        List&amp;lt;String&amp;gt; filteredNames = names.stream()
                .filter(name -&amp;gt; name.startsWith(&quot;J&quot;))
                .toList(); // collect(Collectors.toList()) same Code 같은 동작화는 코드

        System.out.println(filteredNames.toString());

        //Mapping - 데이터 컬렉션의 요소를 다른 형태로 변환
        List&amp;lt;Integer&amp;gt; nameLengths = names.stream()
                .map(String::length)
                .toList();

        System.out.println(nameLengths);

        //Sorting - 데이터 컬렉션의 요소를 정렬
        List&amp;lt;String&amp;gt; sortedNames = names.stream()
                .sorted()
                .toList();

        System.out.println(sortedNames.toString());

        //Grouping - 데이터 컬렉션의 요소를 특정 기준으로 그룹화
        Map&amp;lt;Integer, List&amp;lt;String&amp;gt;&amp;gt; namesByLength = names.stream()
                .collect(Collectors.groupingBy(String::length));

        System.out.println(namesByLength.toString());

        //Reducing - 데이터 컬렉션의 모든 요소를 하나로
        Optional&amp;lt;Integer&amp;gt; sum = numbers.stream()
                .reduce(Integer::sum);

        System.out.println(sum.toString());

        //Processing - 데이터 컬렉션을 병렬로 처리
        int sumValue = numbers.parallelStream()
                .mapToInt(Integer::intValue)
                .sum();

        System.out.println(sumValue);

        //Stream Concatenation - 두 개의 스트림을 연결
        List&amp;lt;String&amp;gt; firstNames = Arrays.asList(&quot;John&quot;, &quot;Doe&quot;);
        List&amp;lt;String&amp;gt; lastNames = Arrays.asList(&quot;Smith&quot;, &quot;Johnson&quot;);
        Stream&amp;lt;String&amp;gt; concatenatedStream = Stream.concat(firstNames.stream(), lastNames.stream());

        System.out.println(concatenatedStream);


    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 추가된 기능이 많으니 책 또는 오라클 Docs에서 꼭 확인하도록 하자 !!  &lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ref&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블로그에서 사용한 코드 github (더 좋은 예제가 있다면 PR 또는 댓글 남겨주세요 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/modern-java-practice&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/DongJu-Na/modern-java-practice&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1711205106189&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - DongJu-Na/modern-java-practice: Example project to practice modern Java&quot; data-og-description=&quot;Example project to practice modern Java. Contribute to DongJu-Na/modern-java-practice development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/DongJu-Na/modern-java-practice&quot; data-og-url=&quot;https://github.com/DongJu-Na/modern-java-practice&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bGMPb5/hyVDGj27Q9/OQFv4xBQTMuwkQ7xjWtMw1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/modern-java-practice&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/DongJu-Na/modern-java-practice&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bGMPb5/hyVDGj27Q9/OQFv4xBQTMuwkQ7xjWtMw1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - DongJu-Na/modern-java-practice: Example project to practice modern Java&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Example project to practice modern Java. Contribute to DongJu-Na/modern-java-practice development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;최신 Java/JVM 빌드 사례&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/binkley/modern-java-practices&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/binkley/modern-java-practices&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1711030649753&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - binkley/modern-java-practices: Modern Java/JVM Build Practices&quot; data-og-description=&quot;Modern Java/JVM Build Practices. Contribute to binkley/modern-java-practices development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/binkley/modern-java-practices&quot; data-og-url=&quot;https://github.com/binkley/modern-java-practices&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bhyx8i/hyVDBimDP2/C5SeI4OjuZ1sUPJJsyGkck/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/binkley/modern-java-practices&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/binkley/modern-java-practices&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bhyx8i/hyVDBimDP2/C5SeI4OjuZ1sUPJJsyGkck/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - binkley/modern-java-practices: Modern Java/JVM Build Practices&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Modern Java/JVM Build Practices. Contribute to binkley/modern-java-practices development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 프로그래머다 웨비너 - 자바8 깊숙히! &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;- 케빈(Kevin Lee 영상도 이어서 보길 추천!)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=lIEKOe0bh0M&amp;amp;t=0s&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=lIEKOe0bh0M&amp;amp;t=10s&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=lIEKOe0bh0M&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/qzpeP/hyVABRRimT/kLegtK8wb0QcelCyi0Jcf0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=552_318_704_484&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/lIEKOe0bh0M&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;[10분&amp;nbsp;테코톡]&amp;nbsp;그레이,&amp;nbsp;호이의&amp;nbsp;Modern&amp;nbsp;Java&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=veJO12VV-Mg&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=veJO12VV-Mg&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=veJO12VV-Mg&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bJhSTa/hyVAIKeWWs/kPXNWFIbJ0QmeZpNvq0ck0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=712_358_1118_456&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/veJO12VV-Mg&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&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;&lt;a href=&quot;https://www.manning.com/books/modern-java-in-action&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.manning.com/books/modern-java-in-action&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1711033133078&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Modern Java in Action&quot; data-og-description=&quot;Manning&amp;rsquo;s bestselling Java 8 book has been revised for Java 9 and 10! In it, you&amp;rsquo;ll build on your existing Java language skills with the newest features and techniques.&quot; data-og-host=&quot;www.manning.com&quot; data-og-source-url=&quot;https://www.manning.com/books/modern-java-in-action&quot; data-og-url=&quot;https://www.manning.com/books/modern-java-in-action&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bBHLDg/hyVABdfkCx/Ibs1BI0p1FafkwgCKsEdeK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/3HM2x/hyVABj0RvZ/FnRdKE2eIyuo7WAg1Kvn4k/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/CErLa/hyVAKut83Q/0eLeh2dPxGfhmfGdVun1qk/img.jpg?width=264&amp;amp;height=331&amp;amp;face=0_0_264_331&quot;&gt;&lt;a href=&quot;https://www.manning.com/books/modern-java-in-action&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.manning.com/books/modern-java-in-action&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bBHLDg/hyVABdfkCx/Ibs1BI0p1FafkwgCKsEdeK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/3HM2x/hyVABj0RvZ/FnRdKE2eIyuo7WAg1Kvn4k/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/CErLa/hyVAKut83Q/0eLeh2dPxGfhmfGdVun1qk/img.jpg?width=264&amp;amp;height=331&amp;amp;face=0_0_264_331');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Modern Java in Action&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Manning&amp;rsquo;s bestselling Java 8 book has been revised for Java 9 and 10! In it, you&amp;rsquo;ll build on your existing Java language skills with the newest features and techniques.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.manning.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1711214525077&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference&quot; data-og-description=&quot;Get Free Tier with no time limits on a selection of Always Free services like Autonomous Database, Compute, and Storage, and US$300 in free credits to try additional cloud services.&quot; data-og-host=&quot;developer.oracle.com&quot; data-og-source-url=&quot;https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference&quot; data-og-url=&quot;https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Get Free Tier with no time limits on a selection of Always Free services like Autonomous Database, Compute, and Storage, and US$300 in free credits to try additional cloud services.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://d2.naver.com/helloworld/4911107&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://d2.naver.com/helloworld/4911107&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>Java</category>
      <category>jdk</category>
      <category>jdk 1.8</category>
      <category>modern java</category>
      <category>람다</category>
      <category>모던 자바</category>
      <category>백엔드 면접</category>
      <category>스트림</category>
      <category>자바8</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/33</guid>
      <comments>https://djlife.tistory.com/33#entry33comment</comments>
      <pubDate>Sun, 24 Mar 2024 03:21:56 +0900</pubDate>
    </item>
    <item>
      <title>[모니터링] 프로메테우스 + 그라파나 모니터링 시스템 구축하기 (feat  micrometer)</title>
      <link>https://djlife.tistory.com/32</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;282488.webp&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z94QF/btsEQTgmLP1/SPS1arijJBmleSuwWVNU0k/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z94QF/btsEQTgmLP1/SPS1arijJBmleSuwWVNU0k/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z94QF/btsEQTgmLP1/SPS1arijJBmleSuwWVNU0k/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ94QF%2FbtsEQTgmLP1%2FSPS1arijJBmleSuwWVNU0k%2Fimg.webp&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;256&quot; height=&quot;256&quot; data-filename=&quot;282488.webp&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 전에 만든 스프링 배치+스케줄러에서 호출하는 API 퍼포먼스 측정을 위해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CTO님이 WAS 모니터링 환경을 구성하는 업무를 지시하였다.&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;/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;/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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 할 생각이 없었던 지라 설치부터는 사진을 남기지 않았다..  &amp;zwj;♂️&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;blockquote style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;프로메테우스를 통하여 메트릭 정보를 수집하고&lt;/blockquote&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그라파나로 수집한 데이터를 시각화 하여 모니터링 환경을 구성한다!&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나는 centos 에 구성하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서... &lt;b&gt;프로메테우스(Prometheus)&lt;/b&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;&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 style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #23527c;&quot; href=&quot;https://github.com/prometheus&quot;&gt;Prometheus 는 원래&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/a&gt;&lt;a style=&quot;color: #337ab7;&quot; href=&quot;https://soundcloud.com/&quot;&gt;SoundCloud&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에서 구축된 오픈 소스 시스템 모니터링 및 경고 툴킷입니다&lt;span&gt;&amp;nbsp;&lt;/span&gt;. 2012년 시작된 이후 많은 기업과 조직에서 Prometheus를 채택했으며 이 프로젝트에는 매우 활발한 개발자 및 사용자&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #337ab7;&quot; href=&quot;https://prometheus.io/community&quot;&gt;커뮤니티가&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;있습니다 . 이제는 독립형 오픈 소스 프로젝트이며 어떤 회사와도 독립적으로 유지 관리됩니다. 이를 강조하고 프로젝트의 거버넌스 구조를 명확히 하기 위해 Prometheus는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #337ab7;&quot; href=&quot;http://kubernetes.io/&quot;&gt;Kubernetes&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에 이어 두 번째 호스팅 프로젝트로 2016년에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #337ab7;&quot; href=&quot;https://cncf.io/&quot;&gt;Cloud Native Computing Foundation&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에 합류했습니다 .&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Prometheus는 지표를 시계열 데이터로 수집하고 저장합니다. 즉, 지표 정보는 레이블이라고 하는 선택적 키-값 쌍과 함께 기록된 타임스탬프와 함께 저장됩니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;architecture.png&quot; data-origin-width=&quot;1351&quot; data-origin-height=&quot;811&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYQw0C/btsEQbA3MmQ/kw5d3vKyQeXG6HR74YJIG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYQw0C/btsEQbA3MmQ/kw5d3vKyQeXG6HR74YJIG1/img.png&quot; data-alt=&quot;프로메테우스 아키텍처 (출처 : 프로메테우스 공식 홈페이지)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYQw0C/btsEQbA3MmQ/kw5d3vKyQeXG6HR74YJIG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYQw0C%2FbtsEQbA3MmQ%2Fkw5d3vKyQeXG6HR74YJIG1%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;1351&quot; height=&quot;811&quot; data-filename=&quot;architecture.png&quot; data-origin-width=&quot;1351&quot; data-origin-height=&quot;811&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;프로메테우스 아키텍처 (출처 : 프로메테우스 공식 홈페이지)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; 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;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그래서... 그라파나는 뭔가요?  &lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Grafana_logo.svg.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1045&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ClDyc/btsEQR951pC/Ib23NMhdRRnXiaKfhFhI11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ClDyc/btsEQR951pC/Ib23NMhdRRnXiaKfhFhI11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ClDyc/btsEQR951pC/Ib23NMhdRRnXiaKfhFhI11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FClDyc%2FbtsEQR951pC%2FIb23NMhdRRnXiaKfhFhI11%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;1024&quot; height=&quot;1045&quot; data-filename=&quot;Grafana_logo.svg.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1045&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위키백과에서는 그라파나를 아래와 같이 설명하고 있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Grafana&lt;/b&gt;는&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;추가&amp;nbsp;기능이&amp;nbsp;포함된&amp;nbsp;라이선스된&amp;nbsp;GRafana&amp;nbsp;Enterprise&amp;nbsp;버전은&amp;nbsp;셀프&amp;nbsp;호스팅된&amp;nbsp;설치본으로,&amp;nbsp;또는&amp;nbsp;Grafana&amp;nbsp;Labs&amp;nbsp;클라우드&amp;nbsp;서비스의&amp;nbsp;계정으로&amp;nbsp;이용이&amp;nbsp;가능하다.&amp;nbsp;플러그인을&amp;nbsp;통해&amp;nbsp;확장이&amp;nbsp;가능하다.&amp;nbsp;최종&amp;nbsp;사용자는&amp;nbsp;인터랙티브&amp;nbsp;쿼리&amp;nbsp;빌더를&amp;nbsp;사용하여&amp;nbsp;복잡한&amp;nbsp;모니터링&amp;nbsp;대시보드를&amp;nbsp;만들&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;Grafana는&amp;nbsp;타입스크립트&amp;nbsp;기반&amp;nbsp;프론트엔드,&amp;nbsp;Go&amp;nbsp;기반&amp;nbsp;백엔드로&amp;nbsp;나뉜다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 포스팅 할 생각이 없어가지고 리눅스 환경에 Prometheus , Grafana&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cpu 사용률,메모리 사용량 기타 등등 메트릭 정보도 수집하기 위해&amp;nbsp; *&amp;nbsp; &lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Node Exporter&lt;/span&gt;&lt;/b&gt; 도 같이 설치해주자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;* Node Exporter &lt;/b&gt;는 Prometheus와 함께 사용되는 오픈 소스 소프트웨어입니다. Node Exporter는 리눅스 및 Unix 시스템에서 실행되는 서버 리소스 및 운영 체제 메트릭을 수집하는 데 사용됩니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Node Exporter는 CPU 사용률, 메모리 사용량, 디스크 사용량, 네트워크 활동 및 기타 시스템 관련 메트릭과 같은 다양한 정보를 제공합니다. 이러한 메트릭은 Prometheus 서버로 전송되어 모니터링, 경고 및 시각화를 위해 사용될 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 Node Exporter는 서버의 상태와 성능을 모니터링하고 이를 Prometheus나 기타 모니터링 도구를 사용하여 분석하는 데 사용됩니다. 이를 통해 시스템 관리자는 서버의 건강 상태를 파악하고 필요한 조치를 취할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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;&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;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 메트릭 정보를 수집할 gradle 프로젝트에 아래와 같이 의존성을 추가한다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0aTzK/btsES6y3P3z/y5QrNsCYJKanOf1AAO8nIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0aTzK/btsES6y3P3z/y5QrNsCYJKanOf1AAO8nIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0aTzK/btsES6y3P3z/y5QrNsCYJKanOf1AAO8nIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0aTzK%2FbtsES6y3P3z%2Fy5QrNsCYJKanOf1AAO8nIk%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;882&quot; height=&quot;86&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;86&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 프로젝트 application.yml 파일을 열어서 아래와 같이 Spring Actuator 설정을 추가한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1707886087075&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;management:
  endpoints:
    web:
      exposure:
        include: prometheus
  metrics:
    tags:
      application: &quot;ndj-project&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 프로메테우스 설치 경로에 가서 vi 편집기로 prometheus.yml 파일을 열어 편집한다.&lt;/p&gt;
&lt;pre id=&quot;code_1707886304651&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vi prometheus.yml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1707886402726&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;global:
  scrape_interval: 10s

scrape_configs:
  - job_name: &quot;수집한 타임시리즈1&quot;
    metrics_path: &quot;/actuator/prometheus&quot;
    static_configs:
      - targets: [&quot;localhost:포트&quot;]

  - job_name: &quot;수집한 타임시리즈2&quot;
    metrics_path: &quot;/actuator/prometheus&quot;
    static_configs:
      - targets: [&quot;localhost:포트&quot;]

  - job_name: &quot;수집한 타임시리즈3&quot;
    metrics_path: &quot;/actuator/prometheus&quot;
    static_configs:
      - targets: [&quot;localhost:8088&quot;]

  - job_name: &quot;수집한 타임시리즈4&quot;
    metrics_path: &quot;/actuator/prometheus&quot;
    static_configs:
      - targets: [ &quot;localhost:8180&quot; ]

  - job_name: &quot;수집한 타임시리즈5&quot;
    metrics_path: &quot;/actuator/prometheus&quot;
    static_configs:
      - targets: [ &quot;localhost:8380&quot; ]

  - job_name: &quot;수집한 타임시리즈6&quot;
    metrics_path: &quot;/actuator/prometheus&quot;
    static_configs:
      - targets: [ &quot;localhost:포트&quot; ]
  
  - job_name: &quot;수집한 타임시리즈7&quot;
    metrics_path: &quot;/actuator/prometheus&quot;
    static_configs:
      - targets: [ &quot;localhost:포트&quot; ]
  
  - job_name: &quot;수집한 타임시리즈8&quot;
    metrics_path: &quot;/actuator/prometheus&quot;
    static_configs:
      - targets: [ &quot;localhost:포트&quot; ]

  - job_name: &quot;수집한 타임시리즈9&quot;
    metrics_path: &quot;/actuator/prometheus&quot;
    static_configs:
      - targets: [ &quot;localhost:포트&quot; ]



  - job_name: &quot;node_exporter&quot;
    static_configs:
      - targets: [&quot;localhost:포트&quot;]

  - job_name: &quot;prometheus&quot;
    static_configs:
      - targets: [&quot;localhost:포트&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 그라파나에 어드민 계정으로 접속한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(어드민 설정 하는 것도 사진을 남기지 않았기에 어드민 설정 방법은 공식문서 또는 다른 블로그 포스팅을 참고!!)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;admin 계정으로 사용할 계정 role을 변경할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;별도 설정하지 않았다면 어드민 계정 아이디 admin 비밀번호 admin&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;좌측 메뉴에서 톱니바퀴 (Configuration) 메뉴에서 내가 이용할 계정 role 변경 이후 datasource에서 prometheus를 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_어드민설정.png&quot; data-origin-width=&quot;1261&quot; data-origin-height=&quot;561&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dV5Y41/btsESKpCkFJ/cR2KLjzV2W0ydMMpekAz31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dV5Y41/btsESKpCkFJ/cR2KLjzV2W0ydMMpekAz31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dV5Y41/btsESKpCkFJ/cR2KLjzV2W0ydMMpekAz31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdV5Y41%2FbtsESKpCkFJ%2FcR2KLjzV2W0ydMMpekAz31%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;1261&quot; height=&quot;561&quot; data-filename=&quot;edited_어드민설정.png&quot; data-origin-width=&quot;1261&quot; data-origin-height=&quot;561&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1873&quot; data-origin-height=&quot;903&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/esvhr2/btsEPHm9KBG/kY6c0WzEUpRHIwI0kfDFf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/esvhr2/btsEPHm9KBG/kY6c0WzEUpRHIwI0kfDFf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/esvhr2/btsEPHm9KBG/kY6c0WzEUpRHIwI0kfDFf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fesvhr2%2FbtsEPHm9KBG%2FkY6c0WzEUpRHIwI0kfDFf1%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;1873&quot; height=&quot;903&quot; data-origin-width=&quot;1873&quot; data-origin-height=&quot;903&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;977&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oj1R6/btsEQaCFgvy/IU4lmoPJNYFi7ucMLct6fK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oj1R6/btsEQaCFgvy/IU4lmoPJNYFi7ucMLct6fK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oj1R6/btsEQaCFgvy/IU4lmoPJNYFi7ucMLct6fK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Foj1R6%2FbtsEQaCFgvy%2FIU4lmoPJNYFi7ucMLct6fK%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;977&quot; height=&quot;327&quot; data-origin-width=&quot;977&quot; data-origin-height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. + 버튼을 클릭하여 대시보드를 구성하거나&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이미 다른 사용자가 구성해놓은 템플릿을 다운로드 하여 그라파나에 import 하여 이용할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://grafana.com/grafana/dashboards/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://grafana.com/grafana/dashboards/&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;나는 여기서 &lt;a href=&quot;https://grafana.com/grafana/dashboards/4701-jvm-micrometer/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://grafana.com/grafana/dashboards/4701-jvm-micrometer/&lt;/a&gt; 를 이용하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;1822&quot; data-origin-height=&quot;885&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0PtuB/btsEP8x38e5/p7l2YCaoKdqHLfmVFwQKGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0PtuB/btsEP8x38e5/p7l2YCaoKdqHLfmVFwQKGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0PtuB/btsEP8x38e5/p7l2YCaoKdqHLfmVFwQKGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0PtuB%2FbtsEP8x38e5%2Fp7l2YCaoKdqHLfmVFwQKGk%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;1822&quot; height=&quot;885&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1822&quot; data-origin-height=&quot;885&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;잘못된 정보 댓글 남겨주시면 바로 정정하겠습니다 !!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ref&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://prometheus.io/docs/introduction/overview/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://prometheus.io/docs/introduction/overview/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707830040324&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Overview | Prometheus&quot; data-og-description=&quot;An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.&quot; data-og-host=&quot;prometheus.io&quot; data-og-source-url=&quot;https://prometheus.io/docs/introduction/overview/&quot; data-og-url=&quot;https://prometheus.io/docs/introduction/overview/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eaMhek/hyVjfgdDv0/vHVsK7UkkpkDlx1ay8DPdK/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192,https://scrap.kakaocdn.net/dn/Rwb8l/hyVjbkA4AD/aBkZkQWxalivk2bnWPCkw0/img.png?width=1351&amp;amp;height=811&amp;amp;face=0_0_1351_811&quot;&gt;&lt;a href=&quot;https://prometheus.io/docs/introduction/overview/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://prometheus.io/docs/introduction/overview/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eaMhek/hyVjfgdDv0/vHVsK7UkkpkDlx1ay8DPdK/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192,https://scrap.kakaocdn.net/dn/Rwb8l/hyVjbkA4AD/aBkZkQWxalivk2bnWPCkw0/img.png?width=1351&amp;amp;height=811&amp;amp;face=0_0_1351_811');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Overview | Prometheus&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;prometheus.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://github.com/prometheus/prometheus&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/prometheus/prometheus&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707830051569&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - prometheus/prometheus: The Prometheus monitoring system and time series database.&quot; data-og-description=&quot;The Prometheus monitoring system and time series database. - prometheus/prometheus&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/prometheus/prometheus&quot; data-og-url=&quot;https://github.com/prometheus/prometheus&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/onNWj/hyVjbZcfr7/apcwEbgVSXobXGkG0Ea8zK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/prometheus/prometheus&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/prometheus/prometheus&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/onNWj/hyVjbZcfr7/apcwEbgVSXobXGkG0Ea8zK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - prometheus/prometheus: The Prometheus monitoring system and time series database.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The Prometheus monitoring system and time series database. - prometheus/prometheus&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://grafana.com/docs/grafana/latest/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://grafana.com/docs/grafana/latest/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707830081634&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Grafana open source documentation |  Grafana documentation&quot; data-og-description=&quot;Thank you! Your message has been received!&quot; data-og-host=&quot;grafana.com&quot; data-og-source-url=&quot;https://grafana.com/docs/grafana/latest/&quot; data-og-url=&quot;https://grafana.com/docs/grafana/latest/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kY5jf/hyVjeO7Rus/WORsNUK8AVnFvsST1csXKK/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/bDUPrj/hyVjjXdS8T/BoRcFomNLc5JxoOL3tfWjK/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700&quot;&gt;&lt;a href=&quot;https://grafana.com/docs/grafana/latest/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://grafana.com/docs/grafana/latest/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kY5jf/hyVjeO7Rus/WORsNUK8AVnFvsST1csXKK/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/bDUPrj/hyVjjXdS8T/BoRcFomNLc5JxoOL3tfWjK/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Grafana open source documentation | Grafana documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Thank you! Your message has been received!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;grafana.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://github.com/grafana/grafana&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/grafana/grafana&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707841065061&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - grafana/grafana: The open and composable observability and data visualization platform. Visualize metrics, logs, and tr&quot; data-og-description=&quot;The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many mo...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/grafana/grafana&quot; data-og-url=&quot;https://github.com/grafana/grafana&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/RQmPL/hyVjkIEdRD/a3lH7bgLdddWncftLQDJ50/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://github.com/grafana/grafana&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/grafana/grafana&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/RQmPL/hyVjkIEdRD/a3lH7bgLdddWncftLQDJ50/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - grafana/grafana: The open and composable observability and data visualization platform. Visualize metrics, logs, and tr&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many mo...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://micrometer.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://micrometer.io/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707885520214&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Micrometer Application Observability&quot; data-og-description=&quot;Vendor-neutral application observability facade Micrometer provides a facade for the most popular observability systems, allowing you to instrument your JVM-based application code without vendor lock-in. Think SLF4J, but for observability.&quot; data-og-host=&quot;micrometer.io&quot; data-og-source-url=&quot;https://micrometer.io/&quot; data-og-url=&quot;https://micrometer.io/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/q1BN6/hyVjhFheNg/0fKy2eDb7911IwjKiAL071/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/ms1Yr/hyVjodkrA7/zNONXUZqyD3TS8b88kIwF0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://micrometer.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://micrometer.io/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/q1BN6/hyVjhFheNg/0fKy2eDb7911IwjKiAL071/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/ms1Yr/hyVjodkrA7/zNONXUZqyD3TS8b88kIwF0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Micrometer Application Observability&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Vendor-neutral application observability facade Micrometer provides a facade for the most popular observability systems, allowing you to instrument your JVM-based application code without vendor lock-in. Think SLF4J, but for observability.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;micrometer.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/DevOps</category>
      <category>grafana</category>
      <category>jvm</category>
      <category>Micrometer</category>
      <category>monitoring</category>
      <category>prometheus</category>
      <category>WAS 모니터링</category>
      <category>그라파나</category>
      <category>모니터링</category>
      <category>프로메테우스</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/32</guid>
      <comments>https://djlife.tistory.com/32#entry32comment</comments>
      <pubDate>Wed, 14 Feb 2024 14:27:42 +0900</pubDate>
    </item>
    <item>
      <title>스프링 배치(Spring Batch)  시작하기 ! </title>
      <link>https://djlife.tistory.com/31</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img.png&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/psAiF/btsEj6Ijtqa/txZjn8dDeVpolIFNv3yerk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/psAiF/btsEj6Ijtqa/txZjn8dDeVpolIFNv3yerk/img.png&quot; data-alt=&quot;스프링 배치&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/psAiF/btsEj6Ijtqa/txZjn8dDeVpolIFNv3yerk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpsAiF%2FbtsEj6Ijtqa%2FtxZjn8dDeVpolIFNv3yerk%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;761&quot; height=&quot;315&quot; data-filename=&quot;img.png&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스프링 배치&lt;/figcaption&gt;
&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 배치 5가 릴리즈된지 거의 1년이 흘렀는데 이 때는 안보고 있다가..  &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;내가 만들어야 할 프로그램 프로세스 흐름은&amp;nbsp; 이와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램 한 사이클이 돌아가는데 약 2시간 조금&amp;nbsp; 안되게 걸리고 있는 상황인데, ( 마스터 데이터가 늘어날 수록 시간이 곱이 되는 상황) &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;개발 하고 나서 어느점을 보완해야 되는지 설명 하는게 더 빠를 것 같아서 일단 개발한다..&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치 was,api was가 버틸수 있을 지 모르겠다.. 스케줄 시간보다 잡이 더 길어질수도 있는 상황. &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;최대한 스케일 아웃으로 풀어야 하는데.. 머리가 너무 아프다  &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;/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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스프링배치.drawio.png&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;1201&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DqD7B/btsEnQxpJiT/DZ6ODNpuetYUKKpFvEZoC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DqD7B/btsEnQxpJiT/DZ6ODNpuetYUKKpFvEZoC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DqD7B/btsEnQxpJiT/DZ6ODNpuetYUKKpFvEZoC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDqD7B%2FbtsEnQxpJiT%2FDZ6ODNpuetYUKKpFvEZoC1%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;950&quot; height=&quot;1201&quot; data-filename=&quot;스프링배치.drawio.png&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;1201&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 id=&quot;spring-batch-용어-정리&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Spring Batch&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Ch02_SpringBatchArchitecture_Architecture_ProcessFlow.png&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqqZMl/btsEjGwmZzf/1W26OW8tIxUPBMNIaUK7W0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqqZMl/btsEjGwmZzf/1W26OW8tIxUPBMNIaUK7W0/img.png&quot; data-alt=&quot;스프링배치 주요 흐름 이미지 출처 (https://terasoluna-batch.github.io/)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqqZMl/btsEjGwmZzf/1W26OW8tIxUPBMNIaUK7W0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqqZMl%2FbtsEjGwmZzf%2F1W26OW8tIxUPBMNIaUK7W0%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;2048&quot; height=&quot;1443&quot; data-filename=&quot;Ch02_SpringBatchArchitecture_Architecture_ProcessFlow.png&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1443&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스프링배치 주요 흐름 이미지 출처 (https://terasoluna-batch.github.io/)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #374151; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;스프링 배치 (Spring Batch):&lt;/b&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;/li&gt;
&lt;li&gt;스프링 배치는 배치 작업을 트랜잭션 처리와 함께 관리하고, 실패한 작업을 복구하고 재시작할 수 있는 기능을 제공&lt;/li&gt;
&lt;li&gt;잡(Job), 스텝(Step), 리더(Reader), 프로세서(Processor), 라이터(Writer) 등의 개념을 이용하여 배치 처리를 설계하고 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쿼츠 (Quartz):&lt;/b&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;/li&gt;
&lt;li&gt;주기적으로 실행되어야 하는 작업이나 예약된 작업을 관리하고 실행하는 데 사용&lt;/li&gt;
&lt;li&gt;쿼츠는 크론 표현식을 사용하여 실행 스케줄을 설정하고, 다양한 트리거(trigger)를 통해 작업을 실행할 수 있음&lt;/li&gt;
&lt;li&gt;분산 환경에서도 사용할 수 있는 확장 가능한 아키텍처를 가지고 있어, 대규모 시스템에서도 유연하게 활용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;요약하자면, 스프링 배치는 대규모 데이터 처리를 위한 일괄 처리 프레임워크이고, 쿼츠는 예약된 작업을 스케줄링하고 실행하는 데 사용되는 라이브러리 함께 사용되어 시스템에서 정기적인 작업 처리와 스케줄링을 효과적으로 관리할 수 있음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;job&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;Job&lt;/b&gt; : 전체 배치 프로세스를 캡슐화한 엔티티, 배치 처리 과정을 하나의 단위로 만들어 놓은 객체&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;jobinstance&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;JobInstance&lt;/b&gt; :&lt;span&gt;&amp;nbsp;&lt;/span&gt;Job&lt;span&gt;&amp;nbsp;&lt;/span&gt;실행의 단위(job이 각각 실행할 때마다 따로 추적할 수 있도록 매 실행마다 생성되며 특정 job과 식별 가능한 JobParameters에 상응하는 JobInstance는 단 한 개뿐이다.)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;JobParameters&lt;/b&gt;&amp;nbsp;:&amp;nbsp;JobInstance에&amp;nbsp;전달되는&amp;nbsp;매개변수&amp;nbsp;역할,&amp;nbsp;JobInstance를&amp;nbsp;구분하는&amp;nbsp;식별자&amp;nbsp;역할&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;JobExecution&lt;/b&gt;&amp;nbsp;:&amp;nbsp;Job에&amp;nbsp;대한&amp;nbsp;실행&amp;nbsp;시도&amp;nbsp;정보를&amp;nbsp;담은&amp;nbsp;객체.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;Step&lt;/b&gt;&amp;nbsp;:&amp;nbsp;배치&amp;nbsp;Job의&amp;nbsp;배치처리를&amp;nbsp;정의하고&amp;nbsp;순차적인&amp;nbsp;단계를&amp;nbsp;캡슐화&amp;nbsp;한&amp;nbsp;도메인&amp;nbsp;객체.&amp;nbsp;Job은&amp;nbsp;하나&amp;nbsp;이상의&amp;nbsp;Step을&amp;nbsp;가져야&amp;nbsp;한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;StepExecution&lt;/b&gt;&amp;nbsp;:&amp;nbsp;Step에&amp;nbsp;대한&amp;nbsp;실행&amp;nbsp;시도&amp;nbsp;정보를&amp;nbsp;담은&amp;nbsp;객체.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;ExecutionContext&lt;/b&gt; : 프레임워크에서 유지/관리하는 key-value의 컬렉션. StepExecution객체 또는 JobExecution객체에 속하는 상태를 저장&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;JobExecutionContext&amp;nbsp;&lt;/b&gt;:&amp;nbsp;Commit&amp;nbsp;시점에&amp;nbsp;저장&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;StepExecutionContext&lt;/b&gt;&amp;nbsp;:&amp;nbsp;실행&amp;nbsp;사이에&amp;nbsp;저장&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;JobRepository&lt;/b&gt; :&amp;nbsp;위에&amp;nbsp;업근된&amp;nbsp;모든&amp;nbsp;저장(Persistence)매커니즘을&amp;nbsp;담당.(JobLauncher, Job, Step 구현체에 CRUD 기능을 제공)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;JobLauncher&lt;/b&gt;&amp;nbsp;:&amp;nbsp;주어진&amp;nbsp;JobParameters로&amp;nbsp;Job을&amp;nbsp;실행하는&amp;nbsp;간단한&amp;nbsp;인터페이스.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;Item&amp;nbsp;Reader&lt;/b&gt; :&amp;nbsp;Step에서&amp;nbsp;아이템을&amp;nbsp;한&amp;nbsp;번에&amp;nbsp;하나씩&amp;nbsp;읽어오는&amp;nbsp;작업을&amp;nbsp;추상화한&amp;nbsp;개념&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;Item&amp;nbsp;Writer&lt;/b&gt;&amp;nbsp;:&amp;nbsp;Step에서&amp;nbsp;배치나&amp;nbsp;청크&amp;nbsp;단위로&amp;nbsp;아이템을&amp;nbsp;출력하는&amp;nbsp;작업을&amp;nbsp;추상화한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;Item&amp;nbsp;Processor&lt;/b&gt;&amp;nbsp;:&amp;nbsp;아이템을&amp;nbsp;처리하는&amp;nbsp;비즈니스&amp;nbsp;로직을&amp;nbsp;나타내는&amp;nbsp;추상화&amp;nbsp;개념&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://github.com/spring-projects/spring-batch/wiki/Spring-Batch-5.0-Migration-Guide&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/spring-projects/spring-batch/wiki/Spring-Batch-5.0-Migration-Guide&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706965815419&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Spring Batch 5.0 Migration Guide&quot; data-og-description=&quot;Spring Batch is a framework for writing batch applications using Java and Spring - spring-projects/spring-batch&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/spring-projects/spring-batch/wiki/Spring-Batch-5.0-Migration-Guide&quot; data-og-url=&quot;https://github.com/spring-projects/spring-batch/wiki/Spring-Batch-5.0-Migration-Guide&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cQoZrt/hyVf1PhwKL/jzoQRSncIFeTNnFr6KXohk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/spring-projects/spring-batch/wiki/Spring-Batch-5.0-Migration-Guide&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/spring-projects/spring-batch/wiki/Spring-Batch-5.0-Migration-Guide&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cQoZrt/hyVf1PhwKL/jzoQRSncIFeTNnFr6KXohk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Spring Batch 5.0 Migration Guide&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Spring Batch is a framework for writing batch applications using Java and Spring - spring-projects/spring-batch&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;스프링배치5부터는 매인 애플리케이션에 @EnableBatchProcessing 어노테이션을 사용할 필요가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;자세한 내용은 마이그레이션 가이드부터 읽어 보길 권장한다!!&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;spring-boot-starter-batch,spring-boot-starter-quartz&lt;/b&gt;&amp;nbsp; 배치를 사용하기 위해 배치,쿼츠 종속성 추가&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706964658690&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugins {
	id 'java'
	id 'org.springframework.boot' version '3.2.2'
	id 'io.spring.dependency-management' version '1.1.4'
}

group = 'ndj.batch'
version = '0.0.1-SNAPSHOT'

java {
	sourceCompatibility = '17'
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-batch'
	implementation'org.springframework.boot:spring-boot-starter-quartz'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'com.h2database:h2'
	compileOnly('org.projectlombok:lombok')
	annotationProcessor 'org.projectlombok:lombok'
	testAnnotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.batch:spring-batch-test'
}

tasks.named('test') {
	useJUnitPlatform()
}&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;&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;pre id=&quot;code_1706965433263&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package ndj.batch.demo.job;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;

@Slf4j
@RequiredArgsConstructor
@Configuration
public class SimpleJob {

    @Bean(name = &quot;simpleJob1&quot;)
    public Job simpleJob1(JobRepository jobRepository, Step simpleStep1) {
        log.info(&quot;&amp;gt;&amp;gt;&amp;gt; simpleJob1&quot;);
        return new JobBuilder(&quot;simpleJob1&quot;, jobRepository)
                .start(simpleStep1)
                .build();
    }
    @Bean(&quot;simpleStep1&quot;)
    public Step simpleStep1(JobRepository jobRepository, Tasklet testTasklet, PlatformTransactionManager platformTransactionManager){
        log.info(&quot;&amp;gt;&amp;gt;&amp;gt; simpleStep1&quot;);
        return new StepBuilder(&quot;simpleStep1&quot;, jobRepository)
                .tasklet(testTasklet, platformTransactionManager).build();
    }
    @Bean
    public Tasklet testTasklet(){
        return ((contribution, chunkContext) -&amp;gt; {
            log.info(&quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; Tasklet&quot;);
            return RepeatStatus.FINISHED;
        });
    }
}&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;메타테이블 정보&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 105px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style9&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;BATCH_JOB_EXECUTION&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&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;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;BATCH_JOB_EXECUTION_CONTEXT&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;배치&amp;nbsp;작업&amp;nbsp;실행에&amp;nbsp;필요한&amp;nbsp;컨텍스트&amp;nbsp;정보를&amp;nbsp;저장&amp;nbsp;(예로&amp;nbsp;JobExecutionContext의&amp;nbsp;속성들이&amp;nbsp;여기에&amp;nbsp;저장)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;BATCH_JOB_EXECUTION_PARAMS&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;배치 작업 실행에 전달된 매개변수 정보를 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;BATCH_JOB_INSTANCE&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;배치 작업의 인스턴스에 대한 정보를 저장 (여러 번 실행될 수 있는 동일한 작업의 각 인스턴스를 식별)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;BATCH_STEP_EXECUTION&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&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;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;BATCH_STEP_EXECUTION_CONTEXT&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;배치&amp;nbsp;스텝&amp;nbsp;실행에&amp;nbsp;필요한&amp;nbsp;컨텍스트&amp;nbsp;정보를&amp;nbsp;저장합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 352px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 49.8837%; height: 17px;&quot;&gt;QRTZ_BLOB_TRIGGERS&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 50.1163%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Quartz에서 Blob 형태의 트리거 정보를 저장&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.8837%;&quot;&gt;QRTZ_CALENDARS&lt;/td&gt;
&lt;td style=&quot;width: 50.1163%;&quot;&gt;Quartz&amp;nbsp;캘린더&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;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 49.8837%; height: 17px;&quot;&gt;QRTZ_CRON_TRIGGERS&lt;/td&gt;
&lt;td style=&quot;width: 50.1163%; height: 17px;&quot;&gt;Quartz에서 Cron 표현식을 사용하는 트리거 정보를 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 49.8837%; height: 17px;&quot;&gt;QRTZ_FIRED_TRIGGERS&lt;/td&gt;
&lt;td style=&quot;width: 50.1163%; height: 17px;&quot;&gt;실행된 트리거에 대한 정보를 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 49.8837%; height: 17px;&quot;&gt;QRTZ_JOB_DETAILS&lt;/td&gt;
&lt;td style=&quot;width: 50.1163%; height: 17px;&quot;&gt;&amp;nbsp;Quartz 작업에 대한 상세 정보를 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 49.8837%; height: 17px;&quot;&gt;QRTZ_LOCKS&lt;/td&gt;
&lt;td style=&quot;width: 50.1163%; height: 17px;&quot;&gt;&amp;nbsp;Quartz에서 사용되는 락 정보를 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 49.8837%; height: 17px;&quot;&gt;QRTZ_PAUSED_TRIGGER_GRPS&lt;/td&gt;
&lt;td style=&quot;width: 50.1163%; height: 17px;&quot;&gt;일시 중단된 트리거 그룹에 대한 정보를 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 49.8837%; height: 17px;&quot;&gt;QRTZ_SCHEDULER_STATE&lt;/td&gt;
&lt;td style=&quot;width: 50.1163%; height: 17px;&quot;&gt;Quartz&amp;nbsp;스케줄러의&amp;nbsp;상태&amp;nbsp;정보를&amp;nbsp;저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 49.8837%; height: 17px;&quot;&gt;QRTZ_SIMPLE_TRIGGERS&lt;/td&gt;
&lt;td style=&quot;width: 50.1163%; height: 17px;&quot;&gt;Quartz에서 간단한 트리거 정보를 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 49.8837%; height: 17px;&quot;&gt;QRTZ_SIMPROP_TRIGGERS&lt;/td&gt;
&lt;td style=&quot;width: 50.1163%; height: 17px;&quot;&gt;Quartz에서 사용되는 특별한 속성을 가진 트리거 정보를 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 49.8837%; height: 17px;&quot;&gt;QRTZ_TRIGGERS&lt;/td&gt;
&lt;td style=&quot;width: 50.1163%; height: 17px;&quot;&gt;Quartz 트리거에 대한 기본 정보를 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 Ref.&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-batch/reference/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.spring.io/spring-batch/reference/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706958304433&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Overview :: Spring Batch&quot; data-og-description=&quot;The reference documentation is divided into several sections:&quot; data-og-host=&quot;docs.spring.io&quot; data-og-source-url=&quot;https://docs.spring.io/spring-batch/reference/&quot; data-og-url=&quot;https://docs.spring.io/spring-batch/reference/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-batch/reference/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.spring.io/spring-batch/reference/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Overview :: Spring Batch&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The reference documentation is divided into several sections:&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html&quot;&gt;https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1706958276484&quot; data-og-image=&quot;&quot; data-og-url=&quot;https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html&quot; data-og-source-url=&quot;https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html&quot; data-og-host=&quot;www.quartz-scheduler.org&quot; data-og-description=&quot;CronTrigger Tutorial Introduction cron is a UNIX tool that has been around for a long time, so its scheduling capabilities are powerful and proven. The CronTrigger class is based on the scheduling capabilities of cron. CronTrigger uses &amp;ldquo;cron expressions&quot; data-og-title=&quot;Cron Trigger Tutorial&quot; data-og-type=&quot;website&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html&quot; data-source-url=&quot;https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('&amp;quot;&amp;quot;');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;Cron Trigger Tutorial&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;CronTrigger Tutorial Introduction cron is a UNIX tool that has been around for a long time, so its scheduling capabilities are powerful and proven. The CronTrigger class is based on the scheduling capabilities of cron. CronTrigger uses &amp;ldquo;cron expressions&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;www.quartz-scheduler.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://terasoluna-batch.github.io/guideline/5.0.0.RELEASE/en/Ch02_SpringBatchArchitecture.html#:~:text=Primary%20components%20of%20Spring%20Batch%20and%20overall%20process%20flow&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://terasoluna-batch.github.io/guideline/5.0.0.RELEASE/en/Ch02_SpringBatchArchitecture.html#:~:text=Primary%20components%20of%20Spring%20Batch%20and%20overall%20process%20flow&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706958321188&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Spring Batch Architecture&quot; data-og-description=&quot;Spring Batch architecture acting as a base for TERASOLUNA Server Framework for Java (5.x) is explained. What is Spring Batch Spring Batch, as the name implies is a batch application framework. Following functions are offered based on DI container of Spring&quot; data-og-host=&quot;terasoluna-batch.github.io&quot; data-og-source-url=&quot;https://terasoluna-batch.github.io/guideline/5.0.0.RELEASE/en/Ch02_SpringBatchArchitecture.html#:~:text=Primary%20components%20of%20Spring%20Batch%20and%20overall%20process%20flow&quot; data-og-url=&quot;https://terasoluna-batch.github.io/guideline/5.0.0.RELEASE/en/Ch02_SpringBatchArchitecture.html#:~:text=Primary%20components%20of%20Spring%20Batch%20and%20overall%20process%20flow&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/SR53V/hyVf1aD7hK/6smLSV7dhg5HQPd2eKAo80/img.png?width=2048&amp;amp;height=1443&amp;amp;face=0_0_2048_1443,https://scrap.kakaocdn.net/dn/8HPff/hyVcdX9efh/UudnAXPlgyUy1dRhmJc8k1/img.png?width=1846&amp;amp;height=1523&amp;amp;face=0_0_1846_1523,https://scrap.kakaocdn.net/dn/bO0Pb3/hyVf28tTSB/6vKq4VD14kSvlglDoh7eB0/img.png?width=730&amp;amp;height=565&amp;amp;face=0_0_730_565&quot;&gt;&lt;a href=&quot;https://terasoluna-batch.github.io/guideline/5.0.0.RELEASE/en/Ch02_SpringBatchArchitecture.html#:~:text=Primary%20components%20of%20Spring%20Batch%20and%20overall%20process%20flow&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://terasoluna-batch.github.io/guideline/5.0.0.RELEASE/en/Ch02_SpringBatchArchitecture.html#:~:text=Primary%20components%20of%20Spring%20Batch%20and%20overall%20process%20flow&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/SR53V/hyVf1aD7hK/6smLSV7dhg5HQPd2eKAo80/img.png?width=2048&amp;amp;height=1443&amp;amp;face=0_0_2048_1443,https://scrap.kakaocdn.net/dn/8HPff/hyVcdX9efh/UudnAXPlgyUy1dRhmJc8k1/img.png?width=1846&amp;amp;height=1523&amp;amp;face=0_0_1846_1523,https://scrap.kakaocdn.net/dn/bO0Pb3/hyVf28tTSB/6vKq4VD14kSvlglDoh7eB0/img.png?width=730&amp;amp;height=565&amp;amp;face=0_0_730_565');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Spring Batch Architecture&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Spring Batch architecture acting as a base for TERASOLUNA Server Framework for Java (5.x) is explained. What is Spring Batch Spring Batch, as the name implies is a batch application framework. Following functions are offered based on DI container of Spring&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;terasoluna-batch.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://github.com/DongJu-Na/spring-batch-skelton&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/DongJu-Na/spring-batch-skelton&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706958345332&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - DongJu-Na/spring-batch-skelton: Spring Batch Skelton Code  &quot; data-og-description=&quot;Spring Batch Skelton Code  . Contribute to DongJu-Na/spring-batch-skelton development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/DongJu-Na/spring-batch-skelton&quot; data-og-url=&quot;https://github.com/DongJu-Na/spring-batch-skelton&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c5Hkfe/hyVf721BUm/VSjssRiC4QJtcMtDaoHhc0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/spring-batch-skelton&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/DongJu-Na/spring-batch-skelton&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c5Hkfe/hyVf721BUm/VSjssRiC4QJtcMtDaoHhc0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - DongJu-Na/spring-batch-skelton: Spring Batch Skelton Code  &lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Spring Batch Skelton Code  . Contribute to DongJu-Na/spring-batch-skelton development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>Java</category>
      <category>JDK17</category>
      <category>spring batch</category>
      <category>배치</category>
      <category>배치 프로그램</category>
      <category>스프링</category>
      <category>스프링 배치</category>
      <category>스프링 배치 사용방법</category>
      <category>스프링 배치 시작</category>
      <category>자바</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/31</guid>
      <comments>https://djlife.tistory.com/31#entry31comment</comments>
      <pubDate>Sat, 3 Feb 2024 22:10:59 +0900</pubDate>
    </item>
    <item>
      <title>테이블 매핑 안 되는 데이터 조회 API 속도 개선하기</title>
      <link>https://djlife.tistory.com/30</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;프로그램의 완성 과정.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;747&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ruAny/btsCQ1Ilot8/hnZYhLy1k66u71Tduz6ggK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ruAny/btsCQ1Ilot8/hnZYhLy1k66u71Tduz6ggK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ruAny/btsCQ1Ilot8/hnZYhLy1k66u71Tduz6ggK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FruAny%2FbtsCQ1Ilot8%2FhnZYhLy1k66u71Tduz6ggK%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;960&quot; height=&quot;747&quot; data-filename=&quot;프로그램의 완성 과정.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;747&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;
&lt;p data-ke-size=&quot;size16&quot;&gt;C 데이터를 이용하여 A,B 데이터를 서로 조인하여 데이터를 가지고 와야 되는 상황&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블 튜닝 x (인덱스나 컬럼 및 외부 테이블 추가가 불가능한 상황)&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;A 마스터 테이블&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B 정보성 테이블&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C 프로젝트 외 API&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;1. 데이터 연관 관계 모두 1:N , 1:N ( 화면에서 표출 될 땐 A-C 1:1 관계로 표출)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&amp;nbsp; 백엔드에서 내부 반복을 통하여 데이터를 조립하는 수 외에는 뾰족한 수가 없음  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.&amp;nbsp; 서버단에서 C데이터를 조회 후 내부 반복 시작&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 내부 반복중 A-B 조인 데이터 C데이터와 조립&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;as_is.png&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;127&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckViLh/btsCTXFdKTr/KuO7JOa5ZiHvykgSTu1ZYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckViLh/btsCTXFdKTr/KuO7JOa5ZiHvykgSTu1ZYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckViLh/btsCTXFdKTr/KuO7JOa5ZiHvykgSTu1ZYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckViLh%2FbtsCTXFdKTr%2FKuO7JOa5ZiHvykgSTu1ZYK%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;1917&quot; height=&quot;127&quot; data-filename=&quot;as_is.png&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;127&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;to-be.png&quot; data-origin-width=&quot;1899&quot; data-origin-height=&quot;251&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZsuHH/btsCReAMDWE/2kPaLJIjGk0SJSSm24HQf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZsuHH/btsCReAMDWE/2kPaLJIjGk0SJSSm24HQf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZsuHH/btsCReAMDWE/2kPaLJIjGk0SJSSm24HQf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZsuHH%2FbtsCReAMDWE%2F2kPaLJIjGk0SJSSm24HQf0%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;1899&quot; height=&quot;251&quot; data-filename=&quot;to-be.png&quot; data-origin-width=&quot;1899&quot; data-origin-height=&quot;251&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;background-color: #ffffff; color: #1d1c1d; text-align: left;&quot;&gt;as-is 10~9s&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #1d1c1d; text-align: left;&quot;&gt;to-be 5~7s&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 style=&quot;background-color: #ffffff; color: #1d1c1d; text-align: left;&quot;&gt;Sol.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1d1c1d; text-align: left;&quot;&gt;1.조건으로 최대한 데이터 필터링&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1d1c1d; text-align: left;&quot;&gt;2.외부반복보다는 내부반복 이용 (퍼포먼스를 위해)&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 style=&quot;background-color: #ffffff; color: #1d1c1d; text-align: left;&quot;&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>변소</category>
      <category>Java</category>
      <category>백엔드개발</category>
      <category>요구사항</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/30</guid>
      <comments>https://djlife.tistory.com/30#entry30comment</comments>
      <pubDate>Tue, 2 Jan 2024 13:38:56 +0900</pubDate>
    </item>
    <item>
      <title>[백엔드 개발자 면접 단골 질문 뿌시기 - 3] 스레드(thread)와 프로세스(process)의 차이를 설명해 줄 수 있어요?  </title>
      <link>https://djlife.tistory.com/29</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;120319_0858_processthred1.webp&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;171&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcj1KT/btsB6ip8ArB/DFXKPj126TQqak7rM3bs4k/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcj1KT/btsB6ip8ArB/DFXKPj126TQqak7rM3bs4k/img.webp&quot; data-alt=&quot;프로세스 vs 스레드 이미지 출처 guru99&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcj1KT/btsB6ip8ArB/DFXKPj126TQqak7rM3bs4k/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbcj1KT%2FbtsB6ip8ArB%2FDFXKPj126TQqak7rM3bs4k%2Fimg.webp&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;601&quot; height=&quot;171&quot; data-filename=&quot;120319_0858_processthred1.webp&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;171&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;프로세스 vs 스레드 이미지 출처 guru99&lt;/figcaption&gt;
&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전공자라면 운영체제(OS) 를 배우기 때문에&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;
&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;이 글을 통해 프로세스와 스레드 개념을 이해하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차이점에 대해 간략하게나마 기억에 남기기 위해&amp;nbsp; 글을 작성해둔다.  &lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p id=&quot;프로그램과-프로세스process&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;0. 프로그램과 프로세스(Process)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10분 테코톡 코다님 영상에서는 프로그램과 프로세스에 대해서 피자집에 간 상황으로 비유하고 있는데&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&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 style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; 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;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; 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;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로세스&lt;/b&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;&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;size18&quot;&gt;&lt;b&gt;1. 프로세스와 스레드의 정의&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 55px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;프로세스 (Process)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;스레드 (Thread)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #373e48; text-align: left;&quot;&gt;운영체제로부터 자원을 할당받은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;작업의 단위&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;프로세스가&amp;nbsp;할당받은&amp;nbsp;자원을&amp;nbsp;이용하는&amp;nbsp;실행&amp;nbsp;흐름의&amp;nbsp;단위&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;process&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Process&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Process는 위의 프로그램과 프로세스에서 알아봤다&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;우리는 컴퓨터를 사용할 때 여러개의 프로세스를 사용하려고 한다(코딩을 하면서 음악을 듣는다거나 등등)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; 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;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;thread&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Thread&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; 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;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; 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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;9984B34E5C98844501.png&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IMUjd/btsCOE5RnlF/bKjWvwRec45WOPZAwNNht1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IMUjd/btsCOE5RnlF/bKjWvwRec45WOPZAwNNht1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IMUjd/btsCOE5RnlF/bKjWvwRec45WOPZAwNNht1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIMUjd%2FbtsCOE5RnlF%2FbKjWvwRec45WOPZAwNNht1%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;820&quot; height=&quot;212&quot; data-filename=&quot;9984B34E5C98844501.png&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스레드는 코드, 데이터, 힙 영역을 공통된 자원으로 사용&lt;/b&gt;한다&lt;br /&gt;즉 각 스레드는 각각의 스택만을 사용하는 것이다&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; 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;br /&gt;쉽게 말해 CPU에 프로세스를 모조리 다 빼고, 넣을 필요가 없게 됐다는 말이다&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; 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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 멀티 프로세스와 멀티 스레드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;* &lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;멀티프로세스와 멀티스레드 두 가지 개념이 모두 처리방식의 일종이다&lt;/span&gt; &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1_QiaqQ0HLT4Iy0N608A5mVA.png&quot; data-origin-width=&quot;763&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r9JXf/btsCMxszy43/6p68KiH46uNEAAsp34kxr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r9JXf/btsCMxszy43/6p68KiH46uNEAAsp34kxr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r9JXf/btsCMxszy43/6p68KiH46uNEAAsp34kxr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr9JXf%2FbtsCMxszy43%2F6p68KiH46uNEAAsp34kxr1%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;763&quot; height=&quot;388&quot; data-filename=&quot;1_QiaqQ0HLT4Iy0N608A5mVA.png&quot; data-origin-width=&quot;763&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;multi-process&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Multi-process&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;images_codingbotpark_post_7cc69893-c367-48b0-a1f6-7973c2ab9719_220202-ProcessThread-MultiProcess.png&quot; data-origin-width=&quot;353&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK1xm9/btsCJhKOD9b/aoVTrSqpbSAKKPznd3GPTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK1xm9/btsCJhKOD9b/aoVTrSqpbSAKKPznd3GPTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK1xm9/btsCJhKOD9b/aoVTrSqpbSAKKPznd3GPTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK1xm9%2FbtsCJhKOD9b%2FaoVTrSqpbSAKKPznd3GPTK%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;353&quot; height=&quot;351&quot; data-filename=&quot;images_codingbotpark_post_7cc69893-c367-48b0-a1f6-7973c2ab9719_220202-ProcessThread-MultiProcess.png&quot; data-origin-width=&quot;353&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 여러 사용자가 로그인을 요청하는 상황이 있다&lt;br /&gt;&lt;b&gt;한 프로세스는 매번 하나의 로그인만 처리 할 수 있기 때문에 동시에 처리할 수 없다&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그래서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;부모 프로세스가 fork를 해서 자식 여러 개의 자식 프로세스를 만들어 일을 처리하도록 한다&lt;/b&gt;&lt;br /&gt;이 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자식프로세스는 부모와 별개의 메모리 영역을 확보&lt;/b&gt;하게 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;multi-thread&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Multi-thread&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Multi-thread는 위의 Multi-process와 다르게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;한 프로세스 내에서 구분지어진 실행 단위&lt;/b&gt;라고 할 수 있다&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;images_codingbotpark_post_e981e4ae-e13d-461f-acfc-d9bb303346a6_220202-ProcessThread-MultiThread.png&quot; data-origin-width=&quot;367&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CTWgV/btsCOyR5KuZ/EVh9ltqAqRCM5QGLOWKatk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CTWgV/btsCOyR5KuZ/EVh9ltqAqRCM5QGLOWKatk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CTWgV/btsCOyR5KuZ/EVh9ltqAqRCM5QGLOWKatk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCTWgV%2FbtsCOyR5KuZ%2FEVh9ltqAqRCM5QGLOWKatk%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;367&quot; height=&quot;351&quot; data-filename=&quot;images_codingbotpark_post_e981e4ae-e13d-461f-acfc-d9bb303346a6_220202-ProcessThread-MultiThread.png&quot; data-origin-width=&quot;367&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&quot;실행단위는-프로세스일-수도-있고-스레드일-수도-있다&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;실행단위는 프로세스일 수도 있고, 스레드일 수도 있다&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; 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;br /&gt;이 때 실행단위는 프로세스 그 자체가 된다&lt;br /&gt;&lt;b&gt;즉 해당 프로세스의 하나밖에 없는 쓰레드가 실행 단위가 되는 것이다&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로세스에서 여러 스레드로 실행단위가 나누어지면 멀티 스레드&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;multi-process와-multi-thread의-특징&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2-1. Multi-process와 Multi-thread의 특징&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img.png&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;391&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zpwlV/btsCEKzX589/T2rcfn4CN2ZmO9eJ1NKwC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zpwlV/btsCEKzX589/T2rcfn4CN2ZmO9eJ1NKwC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zpwlV/btsCEKzX589/T2rcfn4CN2ZmO9eJ1NKwC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzpwlV%2FbtsCEKzX589%2FT2rcfn4CN2ZmO9eJ1NKwC1%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;712&quot; height=&quot;391&quot; data-filename=&quot;img.png&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;391&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Multi-process&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 프로세스는 독립적&lt;/li&gt;
&lt;li&gt;IPC를 사용한 통신&lt;/li&gt;
&lt;li&gt;자원 소모적, 개별 메로리 차지&lt;/li&gt;
&lt;li&gt;Context Switching 비용이 큼&lt;/li&gt;
&lt;li&gt;동기화 작업이 필요하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Multi-thread&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Thread끼리 긴밀하게 연결되어 있음&lt;/li&gt;
&lt;li&gt;공유된 자원으로 통신 비용 절감&lt;/li&gt;
&lt;li&gt;공유된 자원으로 메모리가 효율적임&lt;/li&gt;
&lt;li&gt;Context Switching 비용이 적음&lt;/li&gt;
&lt;li&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 용어 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 단위 - cpu core에서 실행하는 하나의 단위로 프로세스와 스레드를 포괄하는 개념&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;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ref&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.guru99.com/difference-between-process-and-thread.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.guru99.com/difference-between-process-and-thread.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1702818553445&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Process vs Thread &amp;ndash; Difference Between Them&quot; data-og-description=&quot;What is a Process? A process is the execution of a program that allows you to perform the appropriate actions specified in a program. It can be defined as an execution unit where a program runs. The O&quot; data-og-host=&quot;www.guru99.com&quot; data-og-source-url=&quot;https://www.guru99.com/difference-between-process-and-thread.html&quot; data-og-url=&quot;https://www.guru99.com/difference-between-process-and-thread.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/chdkBp/hyUPKGSVEK/fnri0395xZvCun0aU4G5wk/img.png?width=601&amp;amp;height=171&amp;amp;face=0_0_601_171,https://scrap.kakaocdn.net/dn/iumVc/hyUPFr3hzT/x93kvg2kMnNKoDSoVbbNak/img.png?width=601&amp;amp;height=171&amp;amp;face=0_0_601_171&quot;&gt;&lt;a href=&quot;https://www.guru99.com/difference-between-process-and-thread.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.guru99.com/difference-between-process-and-thread.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/chdkBp/hyUPKGSVEK/fnri0395xZvCun0aU4G5wk/img.png?width=601&amp;amp;height=171&amp;amp;face=0_0_601_171,https://scrap.kakaocdn.net/dn/iumVc/hyUPFr3hzT/x93kvg2kMnNKoDSoVbbNak/img.png?width=601&amp;amp;height=171&amp;amp;face=0_0_601_171');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Process vs Thread &amp;ndash; Difference Between Them&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;What is a Process? A process is the execution of a program that allows you to perform the appropriate actions specified in a program. It can be defined as an execution unit where a program runs. The O&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.guru99.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://devlog-wjdrbs96.tistory.com/145&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://devlog-wjdrbs96.tistory.com/145&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1703431434019&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java] 프로세스(process)와 쓰레드(Thread)의 개념과 구현&quot; data-og-description=&quot;프로세스(process)란 간단히 말해서 '실행 중인 프로그램(program)'이다. 프로그램을 실행하면 OS로부터 실행에 필요한 자원(메모리)을 할당받아 프로세스가 된다. 그리고 프로그램을 수행하는 데 필&quot; data-og-host=&quot;devlog-wjdrbs96.tistory.com&quot; data-og-source-url=&quot;https://devlog-wjdrbs96.tistory.com/145&quot; data-og-url=&quot;https://devlog-wjdrbs96.tistory.com/145&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bnj1fo/hyUPOxtmRk/SoNxKBPAJkaFX7866KSb2k/img.png?width=800&amp;amp;height=424&amp;amp;face=0_0_800_424,https://scrap.kakaocdn.net/dn/cvyzH6/hyUTLlwz7l/CwNWUsAnCcGkyjzs8CBy3K/img.png?width=800&amp;amp;height=424&amp;amp;face=0_0_800_424,https://scrap.kakaocdn.net/dn/zdbj0/hyUPAMKJGS/Z8cR37qELdLhYbes0VNjKK/img.png?width=2991&amp;amp;height=1588&amp;amp;face=0_0_2991_1588&quot;&gt;&lt;a href=&quot;https://devlog-wjdrbs96.tistory.com/145&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devlog-wjdrbs96.tistory.com/145&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bnj1fo/hyUPOxtmRk/SoNxKBPAJkaFX7866KSb2k/img.png?width=800&amp;amp;height=424&amp;amp;face=0_0_800_424,https://scrap.kakaocdn.net/dn/cvyzH6/hyUTLlwz7l/CwNWUsAnCcGkyjzs8CBy3K/img.png?width=800&amp;amp;height=424&amp;amp;face=0_0_800_424,https://scrap.kakaocdn.net/dn/zdbj0/hyUPAMKJGS/Z8cR37qELdLhYbes0VNjKK/img.png?width=2991&amp;amp;height=1588&amp;amp;face=0_0_2991_1588');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java] 프로세스(process)와 쓰레드(Thread)의 개념과 구현&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;프로세스(process)란 간단히 말해서 '실행 중인 프로그램(program)'이다. 프로그램을 실행하면 OS로부터 실행에 필요한 자원(메모리)을 할당받아 프로세스가 된다. 그리고 프로그램을 수행하는 데 필&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devlog-wjdrbs96.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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.youtube.com/watch?v=1grtWKqTn50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=1grtWKqTn50&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=1grtWKqTn50&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/devgxA/hyUTFsU9ZB/e93OGxdOgwqh1acL7EXpy1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=936_170_1020_262&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;[10분 테코톡]   코다의 Process vs Thread&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/1grtWKqTn50&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/CS</category>
      <category>Java</category>
      <category>Process</category>
      <category>Thread</category>
      <category>개발자 면접</category>
      <category>면접</category>
      <category>백엔드 개발자 면접 단골 질문 뿌시기</category>
      <category>스레드</category>
      <category>스레드와 프로세스 차이</category>
      <category>프로세스</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/29</guid>
      <comments>https://djlife.tistory.com/29#entry29comment</comments>
      <pubDate>Thu, 28 Dec 2023 00:32:14 +0900</pubDate>
    </item>
    <item>
      <title>[백엔드 개발자 면접 단골 질문 뿌시기 - 2] JVM(Java Virtual Machine) 에 대해 설명 하세요  </title>
      <link>https://djlife.tistory.com/28</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JVM.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNTyCV/btsB0c9YkEB/lVlgdcuJSli0EwiI7qFqdK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNTyCV/btsB0c9YkEB/lVlgdcuJSli0EwiI7qFqdK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNTyCV/btsB0c9YkEB/lVlgdcuJSli0EwiI7qFqdK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNTyCV%2FbtsB0c9YkEB%2FlVlgdcuJSli0EwiI7qFqdK%2Fimg.jpg&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;1280&quot; height=&quot;720&quot; data-filename=&quot;JVM.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  : JVM에 대해서 설명해줄수 있나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  : 자... 자바.. 버츄얼 머신으로 ..&amp;nbsp; .java(자연어) 를&amp;nbsp; 컴파일러를 통하여 .class(바이트코드) ...&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;  : ...&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;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JAVA개발자라면 주민등록번호처럼 군번처럼&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;
&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;174b0c9e241515974.jpg&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;501&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbnqCx/btsBTYsuaJQ/IFis6Zx4KVvaX50eKe36qk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbnqCx/btsBTYsuaJQ/IFis6Zx4KVvaX50eKe36qk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbnqCx/btsBTYsuaJQ/IFis6Zx4KVvaX50eKe36qk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbnqCx%2FbtsBTYsuaJQ%2FIFis6Zx4KVvaX50eKe36qk%2Fimg.jpg&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;900&quot; height=&quot;501&quot; data-filename=&quot;174b0c9e241515974.jpg&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;501&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;그래서 JVM이 도대체 뭔데?&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Java&amp;nbsp;Virtual&amp;nbsp;Machine(자바&amp;nbsp;가상&amp;nbsp;머신)은&amp;nbsp;&lt;u&gt;Java로&amp;nbsp;개발한&amp;nbsp;프로그램을&amp;nbsp;컴파일하여&amp;nbsp;만들어지는&amp;nbsp;바이트코드를&amp;nbsp;실행시키기&amp;nbsp;위한&amp;nbsp;가상머신이다.&lt;/u&gt;&amp;nbsp;JRE(Java&amp;nbsp;Runtime&amp;nbsp;Environment)에&amp;nbsp;포함되어&amp;nbsp;있으며,&amp;nbsp;Java&amp;nbsp;컴파일러가&amp;nbsp;프론트엔드를&amp;nbsp;담당한다면&amp;nbsp;Java&amp;nbsp;가상&amp;nbsp;머신은&amp;nbsp;코드&amp;nbsp;최적화와&amp;nbsp;백엔드를&amp;nbsp;담당한다(웹이&amp;nbsp;아닌&amp;nbsp;컴파일러의&amp;nbsp;프론트엔드/백엔드를&amp;nbsp;말하는&amp;nbsp;것이다).&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;size18&quot;&gt;&lt;b&gt;JVM이 어떻게 동작하는데?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 개발자가 자바코드를 작성한다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. ( .java ) 인 파일을 자바 컴파일러를 통해 자바 바이트 코드로 컴파일한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 컴파일 된 바이트 코드를 JVM의 Class Loader에 전달한다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4. Class Loader는 동적 로딩을 통해 필요 클래스들을 로딩 및 링크하여 Runtime Data Area에 올린다. (JVM의 메모리)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5. 실행 엔진은 JVM메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와서 실행한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(JVM 구성과 Runtime Data Area 본문은 _Jbee 님께서 정리한 내용을 인용하였습니다.)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;JVM 구성&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드.jfif&quot; data-origin-width=&quot;735&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OjT21/btsB0dnvEzw/kagLW5yzPr35lNzR8RCXRK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OjT21/btsB0dnvEzw/kagLW5yzPr35lNzR8RCXRK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OjT21/btsB0dnvEzw/kagLW5yzPr35lNzR8RCXRK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOjT21%2FbtsB0dnvEzw%2FkagLW5yzPr35lNzR8RCXRK%2Fimg.jpg&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;735&quot; height=&quot;470&quot; data-filename=&quot;다운로드.jfif&quot; data-origin-width=&quot;735&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;Class Loader(클래스 로더)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;JVM내로 클래스(.class파일)를 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;Runtime 시에 동적으로 클래스를 로드한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;jar파일 내 저장된 클래스들을 JVM위에 탑재하고 사용하지 않는 클래스들은 메모리에서 삭제한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;(컴파일러 역할)&amp;nbsp;&lt;/span&gt;&lt;span&gt;자바는 동적코드, 컴파일 타임이 아니라 런타임에 참조한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;즉, 클래스를 처음으로 참조할 때, 해당 클래스를 로드하고 링크한다는 것이다. &amp;nbsp;&lt;/span&gt;&lt;span&gt;그 역할을 클래스 로더가 수행한다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;Execution Engine(실행 엔진)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;클래스를 실행시키는 역할이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;클래스 로더가 JVM내의 런타임 데이터 영역에 바이트 코드를 배치시키고, 이것은 실행엔진에 의해 실행된다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;자바 바이트코드는 기계가 바로 수행할 수 있는 언어보다는 비교적 인간이 보기 편한 형태로 기술된 것이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;그래서 실행 엔진은 이와 같은 바이트코드를 실제로 JVM내부에서 기계가 실행할 수 있는 형태로 변경한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;이 때 두 가지 방식을 사용하게 된다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;Interpreter(인터프리터)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;실행 엔진은 자바 바이트 코드를 명령어 단위로 읽어서 실행한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;하지만 이 방식은 인터프리터 언어의 단점을 그대로 갖고 있다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;한 줄 씩 수행하기 때문에 느리다는 것이다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;JIT(Just - In - Time)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;인터프리터 방식의 단점을 보완하기 위해 도입된 JIT 컴파일러이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;인터프리터 방식으로 실행하다가 적절한 시점에 바이트코드 전체를 컴파일하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;i&gt;&lt;span&gt;네이티브 코드&lt;/span&gt;&lt;/i&gt;&lt;span&gt;로 변경하고,&amp;nbsp;&lt;/span&gt;&lt;span&gt;이후에는 해당 더 이상 인터프리팅 하지 않고 네이티브 코드로 직접 실행하는 방식이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;네이티브 코드는 캐시에 보관하기 때문에 한 번 컴파일된 코드는 빠르게 수행하게 된다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;물론 JIT컴파일러가 컴파일하는 과정은 바이트코드를 인터프리팅하는 것보다 훨씬 오래걸리므로&amp;nbsp;&lt;/span&gt;&lt;span&gt;한 번만 실행되는 코드라면 컴파일하지 않고 인터프리팅하는 것이 유리하다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;따라서 JIT 컴파일러를 사용하는 JVM들은 내부적으로 해당 메서드가 얼마나 자주 수행되는지 체크하고,&amp;nbsp;&lt;/span&gt;&lt;span&gt;일정 정도를 넘을 때에만 컴파일을 수행한다.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;Garbage collector&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;&lt;span&gt;GC를 수행하는 모듈 (쓰레드)이 있다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Runtime Data Area&lt;/b&gt;&lt;/div&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span&gt;프로그램을 수행하기 위해 OS에서 할당받은 메모리 공간&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;503&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yW900/btsBTZZem0m/JeT8uU5Y1UhqQsLTyk19sk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yW900/btsBTZZem0m/JeT8uU5Y1UhqQsLTyk19sk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yW900/btsBTZZem0m/JeT8uU5Y1UhqQsLTyk19sk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyW900%2FbtsBTZZem0m%2FJeT8uU5Y1UhqQsLTyk19sk%2Fimg.jpg&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;556&quot; height=&quot;503&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;503&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;1) PC Register&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;Thread 가 시작될 때 생성되며 생성될 때마다 생성되는 공간으로 스레드마다 하나씩 존재한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;Thread가 어떤 부분을 어떤 명령으로 실행해야할 지에 대한 기록을 하는 부분으로 현재 수행 중인 JVM 명령의 주소를 갖는다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;2) JVM 스택 영역&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;프로그램 실행과정에서 임시로 할당되었다가&amp;nbsp;&lt;/span&gt;&lt;span&gt;메소드를 빠져나가면 바로 소멸되는 특성의 데이터를 저장하기 위한 영역이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;각종 형태의 변수나 임시 데이터, 스레드나 메소드의 정보를 저장한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;메소드 호출 시마다 각각의 스택 프레임(그 메서드만을 위한 공간)이 생성된다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;메서드 수행이 끝나면 프레임 별로 삭제를 한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;메소드 안에서 사용되는 값들(local variable)을 저장한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;또 호출된 메소드의 매개변수, 지역변수, 리턴 값 및 연산 시 일어나는 값들을 임시로 저장한다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;3) Native method stack&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;자바 프로그램이 컴파일되어 생성되는 바이트 코드가 아닌 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;JAVA가 아닌 다른 언어로 작성된 코드를 위한 공간이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;JAVA Native Interface를 통해 바이트 코드로 전환하여 저장하게 된다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;일반 프로그램처럼 커널이 스택을 잡아 독자적으로 프로그램을 실행시키는 영역이다. 이 부분을 통해 C code를 실행시켜 Kernel에 접근할 수 있다.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;&lt;span&gt;4) Method Area (=&amp;nbsp;C&lt;/span&gt;&lt;span&gt;&lt;span&gt;lass area = Static area)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;클래스 정보를 처음 메모리 공간에 올릴 때&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;초기화되는 대상을 저장하기 위한 메모리 공간&lt;/b&gt;.&amp;nbsp;&lt;/span&gt;&lt;span&gt;올라가게 되는 메소드의 바이트 코드는 프로그램의 흐름을 구성하는 바이트 코드이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;자바 프로그램은 main 메소드의 호출에서부터 계속된 메소드의 호출로 흐름을 이어가기 때문이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;대부분 인스턴스의 생성도 메소드 내에서 명령하고 호출한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;사실상 컴파일 된 바이트코드의 대부분이 메소드 바이트코드이기 때문에&amp;nbsp;&lt;/span&gt;&lt;span&gt;거의 모든 바이트코드가 올라간다고 봐도 상관없다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;이 공간에는&amp;nbsp;&lt;b&gt;Runtime Constant Pool&lt;/b&gt;이라는 별도의 관리 영역도 함께 존재한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;이는 상수 자료형을 저장하여 참조하고 중복을 막는 역할을 수행한다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;i&gt;올라가는 정보의 종류&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;1) Field Information&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;멤버변수의 이름, 데이터 타입, 접근 제어자에 대한 정보&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;2) Method Information&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;메소드의 이름, 리턴타입, 매개변수, 접근제어자에 대한 정보&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;3) Type Information&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;class인지 interface인지의 여부 저장 /Type의 속성, 전체 이름, super class의 전체 이름(interface 이거나 object인 경우 제외)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;i&gt;&lt;span&gt;Method Area는 클래스 데이터를 위한 공간이라면 Heap영역이 객체를 위한 공간이다.&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;i&gt;&lt;span&gt;Heap과 마찬가지로 GC의 관리 대상에 포함된다.&amp;nbsp;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;5) Heap( 힙 영역 )&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;객체를 저장하는 가상 메모리 공간이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;new연산자로 생성된 객체와 배열을 저장한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;물론 class area영역에 올라온 클래스들만 객체로 생성할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;힙은 세 부분으로 나눌 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;207&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cM09XN/btsBTX1mz1f/JdNwMNKAlOATSYvoSxQc40/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cM09XN/btsBTX1mz1f/JdNwMNKAlOATSYvoSxQc40/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cM09XN/btsBTX1mz1f/JdNwMNKAlOATSYvoSxQc40/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcM09XN%2FbtsBTX1mz1f%2FJdNwMNKAlOATSYvoSxQc40%2Fimg.jpg&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;746&quot; height=&quot;207&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;207&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;Permanent Generation&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;생성된 객체들의 정보의 주소값이 저장된 공간이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;Class loader에 의해 load되는 Class, Method 등에 대한 Meta 정보가 저장되는 영역이고 JVM에 의해 사용된다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;Reflection을 사용하여 동적으로 클래스가 로딩되는 경우에 사용된다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;내부적으로 Reflection 기능을 자주 사용하는 Spring Framework를 이용할 경우 이영역에 대한 고려가 필요하다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;New/Young 영역&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span&gt;Eden&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 객체들이 최초로 생성되는 공간&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span&gt;Survivor 0 / 1&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: Eden에서 참조되는 객체들이 저장되는 공간&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;Old 영역&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;New area에서 일정 시간 참조되고 있는, 살아남은 객체들이 저장되는 공간&amp;nbsp;&lt;/span&gt;&lt;span&gt;Eden영역에 객체가 가득차게 되면 첫번째 GC(minor GC)가 발생한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;Eden영역에 있는 값들을 Survivor 1 영역에 복사하고 이 영역을 제외한 나머지 영역의 객체를 삭제한다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;인스턴스는 소멸 방법과 소멸 시점이 지역 변수와는 다르기에 힙이라는 별도의 영역에 할당된다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;자바 가상 머신은 매우 합리적으로 인스턴스를 소멸시킨다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;더이상 인스턴스의 존재 이유가 없을 때 소멸시킨다.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;p style=&quot;color: #666666;&quot; 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;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #434a53; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;JVM Internal - Naver D2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/1230&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://d2.naver.com/helloworld/1230&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;JVM - IBM&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.ibm.com/docs/ko/i/7.3?topic=platform-java-virtual-machine&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.ibm.com/docs/ko/i/7.3?topic=platform-java-virtual-machine&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1702481032093&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;JVM(Java Virtual Machine)&quot; data-og-description=&quot;JVM(Java&amp;trade; Virtual Machine)은 IBM&amp;reg; i와 같은 오퍼레이팅 시스템이나 웹 브라우저에 추가할 수 있는 런타임 환경입니다. JVM(Java Virtual Machine)은 Java 컴파일러가 생성하는 명령어를 실행합니다. JVM은 원래&quot; data-og-host=&quot;www.ibm.com&quot; data-og-source-url=&quot;https://www.ibm.com/docs/ko/i/7.3?topic=platform-java-virtual-machine&quot; data-og-url=&quot;https://www.ibm.com/docs/ko/i/7.3?topic=platform-java-virtual-machine&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.ibm.com/docs/ko/i/7.3?topic=platform-java-virtual-machine&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.ibm.com/docs/ko/i/7.3?topic=platform-java-virtual-machine&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JVM(Java Virtual Machine)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;JVM(Java&amp;trade; Virtual Machine)은 IBM&amp;reg; i와 같은 오퍼레이팅 시스템이나 웹 브라우저에 추가할 수 있는 런타임 환경입니다. JVM(Java Virtual Machine)은 Java 컴파일러가 생성하는 명령어를 실행합니다. JVM은 원래&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.ibm.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;guru99 - What&amp;nbsp;is&amp;nbsp;JVM&amp;nbsp;(Java&amp;nbsp;Virtual&amp;nbsp;Machine):&amp;nbsp;Architecture&amp;nbsp;Explained!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.guru99.com/java-virtual-machine-jvm.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.guru99.com/java-virtual-machine-jvm.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1702481125649&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;What is JVM (Java Virtual Machine): Architecture Explained!&quot; data-og-description=&quot;JVM stands for Java Virtual Machine. In this tutorial we learn JVM working. JVM&amp;rsquo;s architecture converts Java bytecode into machines language.&quot; data-og-host=&quot;www.guru99.com&quot; data-og-source-url=&quot;https://www.guru99.com/java-virtual-machine-jvm.html&quot; data-og-url=&quot;https://www.guru99.com/java-virtual-machine-jvm.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/HGrt2/hyUL2aldmg/EtjJnSMzv5nPQ6zHjDbxZ0/img.jpg?width=615&amp;amp;height=109&amp;amp;face=0_0_615_109,https://scrap.kakaocdn.net/dn/FQvrB/hyUL0Q89zn/CyKcgMYvQDmFnL0cSd8a01/img.jpg?width=615&amp;amp;height=109&amp;amp;face=0_0_615_109,https://scrap.kakaocdn.net/dn/bSLhDe/hyUL1oZqQT/D0TJiXUMKKN2mfENL1Ytck/img.png?width=913&amp;amp;height=596&amp;amp;face=0_0_913_596&quot;&gt;&lt;a href=&quot;https://www.guru99.com/java-virtual-machine-jvm.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.guru99.com/java-virtual-machine-jvm.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/HGrt2/hyUL2aldmg/EtjJnSMzv5nPQ6zHjDbxZ0/img.jpg?width=615&amp;amp;height=109&amp;amp;face=0_0_615_109,https://scrap.kakaocdn.net/dn/FQvrB/hyUL0Q89zn/CyKcgMYvQDmFnL0cSd8a01/img.jpg?width=615&amp;amp;height=109&amp;amp;face=0_0_615_109,https://scrap.kakaocdn.net/dn/bSLhDe/hyUL1oZqQT/D0TJiXUMKKN2mfENL1Ytck/img.png?width=913&amp;amp;height=596&amp;amp;face=0_0_913_596');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;What is JVM (Java Virtual Machine): Architecture Explained!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;JVM stands for Java Virtual Machine. In this tutorial we learn JVM working. JVM&amp;rsquo;s architecture converts Java bytecode into machines language.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.guru99.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://docs.oracle.com/en/java/javase/11/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651-CB6475019281&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/en/java/javase/11/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651-CB6475019281&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1702481702093&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Java Virtual Machine Guide&quot; data-og-description=&quot; &quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/en/java/javase/11/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651-CB6475019281&quot; data-og-url=&quot;https://docs.oracle.com/en/java/javase/11/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651-CB6475019281&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651-CB6475019281&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/en/java/javase/11/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651-CB6475019281&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Java Virtual Machine Guide&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://asfirstalways.tistory.com/158&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://asfirstalways.tistory.com/158&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1702482720457&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;#자바가상머신, JVM(Java Virtual Machine)이란 무엇인가?&quot; data-og-description=&quot;#JVM이란?JVM이란 JAVA Virtual Machine, 자바 가상 머신의 약자를 따서 줄여 부르는 용어이다 (가상머신이란 프로그램의 실행하기 위해 물리적 머신과 유사한 머신을 소프트웨어로 구현한 것이다.) JVM &quot; data-og-host=&quot;asfirstalways.tistory.com&quot; data-og-source-url=&quot;https://asfirstalways.tistory.com/158&quot; data-og-url=&quot;https://asfirstalways.tistory.com/158&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/q7KXG/hyULRGHykh/JoeTEvs4WIru5tKKfDrqJ1/img.jpg?width=735&amp;amp;height=470&amp;amp;face=0_0_735_470,https://scrap.kakaocdn.net/dn/nf8z8/hyUL6KDObi/oNmQ2gh8UDJgyWpHAMrH31/img.jpg?width=735&amp;amp;height=470&amp;amp;face=0_0_735_470,https://scrap.kakaocdn.net/dn/bHrF1M/hyULRfDu6W/uj54FmH7NjrdpQHW7Z5OoK/img.jpg?width=735&amp;amp;height=470&amp;amp;face=0_0_735_470&quot;&gt;&lt;a href=&quot;https://asfirstalways.tistory.com/158&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://asfirstalways.tistory.com/158&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/q7KXG/hyULRGHykh/JoeTEvs4WIru5tKKfDrqJ1/img.jpg?width=735&amp;amp;height=470&amp;amp;face=0_0_735_470,https://scrap.kakaocdn.net/dn/nf8z8/hyUL6KDObi/oNmQ2gh8UDJgyWpHAMrH31/img.jpg?width=735&amp;amp;height=470&amp;amp;face=0_0_735_470,https://scrap.kakaocdn.net/dn/bHrF1M/hyULRfDu6W/uj54FmH7NjrdpQHW7Z5OoK/img.jpg?width=735&amp;amp;height=470&amp;amp;face=0_0_735_470');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;#자바가상머신, JVM(Java Virtual Machine)이란 무엇인가?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;#JVM이란?JVM이란 JAVA Virtual Machine, 자바 가상 머신의 약자를 따서 줄여 부르는 용어이다 (가상머신이란 프로그램의 실행하기 위해 물리적 머신과 유사한 머신을 소프트웨어로 구현한 것이다.) JVM&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;asfirstalways.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/CS</category>
      <category>GC</category>
      <category>Java</category>
      <category>java 8</category>
      <category>java virtual machine</category>
      <category>jdk</category>
      <category>jvm</category>
      <category>JVM 아키텍처</category>
      <category>갈비지 컬렉터</category>
      <category>백엔드 개발자 면접 단골 질문 뿌시기</category>
      <category>자바 버츄얼 머신</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/28</guid>
      <comments>https://djlife.tistory.com/28#entry28comment</comments>
      <pubDate>Thu, 14 Dec 2023 00:45:30 +0900</pubDate>
    </item>
    <item>
      <title>[백엔드 개발자 면접 단골 질문 뿌시기 - 1] 3계층 아키텍처(3 Tier- Architectur)가 뭘까?</title>
      <link>https://djlife.tistory.com/27</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;MSA 환경에 개발을 하는 회사에서는 아마 면접에서 자주 물어보는 질문일 것이라고 생각이 들어&amp;nbsp;&lt;/span&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;&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;size18&quot;&gt;&amp;nbsp;&lt;b&gt;3계층 아키텍처&lt;/b&gt;란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IBM에서는 이렇게 정의하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;3계층 아키텍처(3 Tier-Architectur)는 애플리케이션을 프레젠테이션 계층 또는 사용자 인터페이스, 데이터가 처리되는 애플리케이션 계층 그리고 애플리케이션과 관련된 데이터가 저장 및 관리되는 데이터 계층이라는 3개의 논리적이고 물리적인 컴퓨팅 계층으로 구성하는 확립된 소프트웨어 애플리케이션 아키텍처입니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&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 Serif KR';&quot;&gt;정의는 알았으니 각 계층에 대해서 상세히 알아보자면  &lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;02-1024x790-1.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;790&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djXIko/btsBF3U6WSV/pIlPkk6UoOb5yn6DriKTR0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djXIko/btsBF3U6WSV/pIlPkk6UoOb5yn6DriKTR0/img.webp&quot; data-alt=&quot;3Tier Architecture - logianalytics.com&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djXIko/btsBF3U6WSV/pIlPkk6UoOb5yn6DriKTR0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjXIko%2FbtsBF3U6WSV%2FpIlPkk6UoOb5yn6DriKTR0%2Fimg.webp&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;1024&quot; height=&quot;790&quot; data-filename=&quot;02-1024x790-1.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;790&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;3Tier Architecture - logianalytics.com&lt;/figcaption&gt;
&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #161616; text-align: start;&quot; 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;- 웹 브라우저, 데스크탑 애플리케이션 또는 그래픽 사용자 인터페이스(GUI)에서 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 일반적으로 HTML,CSS,JS를 사용하여 개발 ( &lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;React, Angular, Ember,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;s&gt;Aurora&lt;/s&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;, Vue ,&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Svelte&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #212529; text-align: left;&quot;&gt; 프레임워크 사용)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #161616; text-align: start;&quot; 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;span style=&quot;background-color: #ffffff; color: #161616; text-align: left;&quot;&gt;사용자 입력을 처리하는 데 사용되는 비즈니스 논리를 수용하는 중간 계층&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp; 일반적으로 Java,C++,Python,Ruby 개발&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #161616; text-align: start;&quot; 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;- MSSQL,MYSQL,ORACLE,PostgreSQL&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;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3계층 아키텍처의 간단한 예&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #212529;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt; &lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;CGV 사이트에서&lt;/span&gt;&amp;nbsp; 영화를 예매한다고 가정하면&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;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;프레젠테이션 계층&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;- CGV 사이트&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;애플리케이션 계층&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CGV 사이트에서 영화를 예매한 정보들이 애플리케이션 계층에 넘어와서 비지니스 로직을 거쳐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터베이스 계층&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3계층 아키텍처를 사용했을 경우 얻을 수 있는 &lt;span style=&quot;color: #006dd7;&quot;&gt;장점&lt;/span&gt;과 &lt;span style=&quot;color: #ee2323;&quot;&gt;단점&lt;/span&gt;&lt;/b&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;장점&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.각 계층을 담당하는 팀들을 구성하여 업무 분담이 가능하다. (업무 효율성 증가)&lt;br /&gt;2.프레젠테이션 계층과 데이터 계층끼리 직접 통신할 수 없다. (보안성 강화)&lt;br /&gt;3.한 계층의 가동 중단은 다른 계층의 성능에 별로 영향을 끼치지 않는다. (안정성 향상)&lt;br /&gt;4.필요에 따라 임의의 계층을 다른 계층과는 독립접으로 확장할 수 있다.&amp;nbsp; (확장성 개선)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 많아진 계층으로 인해 그만큼 많은 관리 포인트가 생긴다. (비용 증가)&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;&lt;br /&gt;따라서&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;한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.ibm.com/kr-ko/topics/three-tier-architecture&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.ibm.com/kr-ko/topics/three-tier-architecture&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1702352220730&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;3계층 아키텍처란? | IBM&quot; data-og-description=&quot;3계층 아키텍처는 애플리케이션을 프리젠테이션 계층, 애플리케이션 계층 및 데이터 계층으로 분리합니다.&quot; data-og-host=&quot;www.ibm.com&quot; data-og-source-url=&quot;https://www.ibm.com/kr-ko/topics/three-tier-architecture&quot; data-og-url=&quot;https://www.ibm.com/kr-ko/topics/three-tier-architecture&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cPEiwS/hyULZqNokk/zOS41iR8bQ2jPSigNzkKa0/img.png?width=1312&amp;amp;height=464&amp;amp;face=0_0_1312_464&quot;&gt;&lt;a href=&quot;https://www.ibm.com/kr-ko/topics/three-tier-architecture&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.ibm.com/kr-ko/topics/three-tier-architecture&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cPEiwS/hyULZqNokk/zOS41iR8bQ2jPSigNzkKa0/img.png?width=1312&amp;amp;height=464&amp;amp;face=0_0_1312_464');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;3계층 아키텍처란? | IBM&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;3계층 아키텍처는 애플리케이션을 프리젠테이션 계층, 애플리케이션 계층 및 데이터 계층으로 분리합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.ibm.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://insightsoftware.com/blog/5-benefits-of-a-3-tier-architecture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://insightsoftware.com/blog/5-benefits-of-a-3-tier-architecture/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1702352237711&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;5 Benefits of a 3-Tier Architecture&quot; data-og-description=&quot;To keep up with the pace of change required to deliver a compelling software product and to leverage emerging technologies, a microservices or three-tier architecture provides numerous benefits. It allows a developer the opportunity to extend, modularize, &quot; data-og-host=&quot;insightsoftware.com&quot; data-og-source-url=&quot;https://insightsoftware.com/blog/5-benefits-of-a-3-tier-architecture/&quot; data-og-url=&quot;https://insightsoftware.com/blog/5-benefits-of-a-3-tier-architecture/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bSSie3/hyUL3Nvpje/jY06mLquZaF1JJWXelmJCK/img.png?width=1024&amp;amp;height=790&amp;amp;face=0_0_1024_790&quot;&gt;&lt;a href=&quot;https://insightsoftware.com/blog/5-benefits-of-a-3-tier-architecture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://insightsoftware.com/blog/5-benefits-of-a-3-tier-architecture/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bSSie3/hyUL3Nvpje/jY06mLquZaF1JJWXelmJCK/img.png?width=1024&amp;amp;height=790&amp;amp;face=0_0_1024_790');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;5 Benefits of a 3-Tier Architecture&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;To keep up with the pace of change required to deliver a compelling software product and to leverage emerging technologies, a microservices or three-tier architecture provides numerous benefits. It allows a developer the opportunity to extend, modularize,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;insightsoftware.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/CS</category>
      <category>3 Tier- Architectur</category>
      <category>3계층 아키텍처</category>
      <category>backend</category>
      <category>MSA</category>
      <category>개발자 면접</category>
      <category>개발자 면접 질문</category>
      <category>면접</category>
      <category>백엔드</category>
      <category>백엔드 개발자 면접 단골 질문 뿌시기</category>
      <category>백엔드 면접 준비</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/27</guid>
      <comments>https://djlife.tistory.com/27#entry27comment</comments>
      <pubDate>Tue, 12 Dec 2023 14:41:52 +0900</pubDate>
    </item>
    <item>
      <title>아파치 카프카(APACHE Kafka) 그게 도대체 뭔데   카프카 기본 개념에 대해 알아보자</title>
      <link>https://djlife.tistory.com/26</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;apache_kafka.jpeg&quot; data-origin-width=&quot;2400&quot; data-origin-height=&quot;1342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dkvpAw/btsz92i71so/wXN6VRLf4Cf8GsmO0Orntk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkvpAw/btsz92i71so/wXN6VRLf4Cf8GsmO0Orntk/img.jpg&quot; data-alt=&quot;아파치 카프카 로고&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkvpAw/btsz92i71so/wXN6VRLf4Cf8GsmO0Orntk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdkvpAw%2Fbtsz92i71so%2FwXN6VRLf4Cf8GsmO0Orntk%2Fimg.jpg&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;2400&quot; height=&quot;1342&quot; data-filename=&quot;apache_kafka.jpeg&quot; data-origin-width=&quot;2400&quot; data-origin-height=&quot;1342&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;아파치 카프카 로고&lt;/figcaption&gt;
&lt;/figure&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 *&lt;b&gt;아파치 카프카(Apache Kafka)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;*정의&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아파치 카프카(Apache Kafka)&lt;/b&gt;는 아파치 소프트웨어 재단이 스칼라로 개발한 오픈 소스 메시지 브로커 프로젝트이다. 이 프로젝트는 실시간 데이터 피드를 관리하기 위해 통일된, &lt;b&gt;높은 처리량&lt;/b&gt;, &lt;b&gt;낮은 지연&lt;/b&gt;시간을 지닌 플랫폼을 제공하는 것이 목표이다. 요컨대 분산 트랜잭션 로그로 구성된, &lt;u&gt;상당히 확장 가능한 pub/sub 메시지 큐로 정의할 수 있으며, 스트리밍 데이터를 처리하기 위한 기업 인프라를 위한 고부가 가치 기능&lt;/u&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;디자인은 트랜잭션 로그에 많은 영향을 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;역사&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;아파치&amp;nbsp;카프카는&amp;nbsp;원래&amp;nbsp;링크드인이&amp;nbsp;개발한&amp;nbsp;것으로,&amp;nbsp;2011년&amp;nbsp;초에&amp;nbsp;최종적으로&amp;nbsp;오픈&amp;nbsp;소스화되었다.&amp;nbsp;2012년&amp;nbsp;10월&amp;nbsp;23일에는&amp;nbsp;아파치&amp;nbsp;인큐베이터로부터&amp;nbsp;완전히&amp;nbsp;빠져나왔다.&amp;nbsp;2014년&amp;nbsp;11월&amp;nbsp;링크드인에서&amp;nbsp;카프카를&amp;nbsp;만들던&amp;nbsp;일부&amp;nbsp;엔지니어들이&amp;nbsp;카프카에&amp;nbsp;집중하기&amp;nbsp;위해&amp;nbsp;Confluent라는&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;span style=&quot;background-color: #fefefe; color: #333333; text-align: start;&quot;&gt;이렇게만 봤을 때는...  &lt;/span&gt;&lt;span style=&quot;background-color: #fefefe; color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fefefe;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;링크드인에서 Kafka를 도입하기 전에는 아래의 아키텍처를 가지고 서비스되었다.&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 style=&quot;color: #212529;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;as-is&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LSgN7/btsAwsAc8JF/5aqiSw4SrIQ9DkwleqMavk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LSgN7/btsAwsAc8JF/5aqiSw4SrIQ9DkwleqMavk/img.png&quot; data-alt=&quot;Before Kafka&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LSgN7/btsAwsAc8JF/5aqiSw4SrIQ9DkwleqMavk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLSgN7%2FbtsAwsAc8JF%2F5aqiSw4SrIQ9DkwleqMavk%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;1280&quot; height=&quot;726&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Before Kafka&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;앤드투엔드(end-to-end) 연결 방식의 아키텍쳐&lt;/li&gt;
&lt;li&gt;데이터 연동의 복잡성 증가(하드웨어, 운영체제 , 장애 등등..)&lt;/li&gt;
&lt;li&gt;각기 다른 데이터 파이프라인 연결 구조&lt;/li&gt;
&lt;li&gt;확장에 엄청난 개발 공수필요&amp;nbsp;&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;/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;to-be&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드2.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;970&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PVjQv/btsAqxwyojl/lybe5JZOUlPnpkeyQBXhC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PVjQv/btsAqxwyojl/lybe5JZOUlPnpkeyQBXhC0/img.png&quot; data-alt=&quot;After Kafka&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PVjQv/btsAqxwyojl/lybe5JZOUlPnpkeyQBXhC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPVjQv%2FbtsAqxwyojl%2Flybe5JZOUlPnpkeyQBXhC0%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;1280&quot; height=&quot;970&quot; data-filename=&quot;다운로드2.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;970&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;After Kafka&lt;/figcaption&gt;
&lt;/figure&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;&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;프로듀서/컨슈머 분리&lt;/li&gt;
&lt;li&gt;메세지 데이터를 여러 컨슈머에게 허용&lt;/li&gt;
&lt;li&gt;높은 처리량을 위한 메세지 최적화&lt;/li&gt;
&lt;li&gt;스케일 아웃 가능&lt;/li&gt;
&lt;li&gt;관련 생태계 제공&lt;/li&gt;
&lt;/ul&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;키워드&amp;nbsp; 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;&lt;b&gt;Producer(프로듀서)&lt;/b&gt; : 메시지 생산자&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;&lt;b&gt;Broker(브로커)&lt;/b&gt; : 메시지 수집/전달 역할&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;&lt;b&gt;Consumer(컨슈머)&lt;/b&gt; : 메시지 소비자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;&lt;b&gt;Topic(토픽)&lt;/b&gt; : 파일시스템에서 폴더 or RDBMS에 table 개념 .. &lt;span style=&quot;background-color: #ffffff; color: #484848; text-align: start;&quot;&gt;Data가 저장되는 곳?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #484848; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Consumer-Group(컨슈머 그룹) &lt;/b&gt;: 메세지 소비자 묶음 단위(n consumers)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #484848; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Zookeeper(주키퍼)&lt;/b&gt; : Kafka를 운용하기 위한 Coordination service(&lt;a style=&quot;color: #0000ff;&quot; href=&quot;http://bcho.tistory.com/1016&quot;&gt;zookeeper 소개&lt;/a&gt;)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #484848; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Partition(파트리언)&lt;/b&gt; : topic이 복사(replicated)되어 나뉘어지는 단위&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;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;사이드프로젝트를 진행하면서 블로깅 할 예정  &lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데브원영님 유튜브 추천&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div id=&quot;reaction-25&quot;&gt;&amp;nbsp;Apache kafka 기본개념 및 생태계&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=catN_YhV6To&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=catN_YhV6To&lt;/a&gt;&lt;/div&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=catN_YhV6To&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/vL7bY/hyUynr8Suc/RTkOLXzkzbe4FUcOQuu07K/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/catN_YhV6To&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&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;&lt;a href=&quot;https://www.youtube.com/watch?v=waw0XXNX-uQ&amp;amp;t=44s&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=waw0XXNX-uQ&amp;amp;t=44s&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=waw0XXNX-uQ&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/rKuVX/hyUypXNjqw/ZgKJUgDCcGKcXQRu6rtnz0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/waw0XXNX-uQ&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카프카 응용 공부 github&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/kafkaStudy&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/DongJu-Na/kafkaStudy&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1700202572903&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - DongJu-Na/kafkaStudy: 카프카 겉핧기&quot; data-og-description=&quot;카프카 겉핧기. Contribute to DongJu-Na/kafkaStudy development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/DongJu-Na/kafkaStudy&quot; data-og-url=&quot;https://github.com/DongJu-Na/kafkaStudy&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cjPwHp/hyUyymUCwN/U92lSjyCljKbHLfm9nKm70/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/kafkaStudy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/DongJu-Na/kafkaStudy&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cjPwHp/hyUyymUCwN/U92lSjyCljKbHLfm9nKm70/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - DongJu-Na/kafkaStudy: 카프카 겉핧기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;카프카 겉핧기. Contribute to DongJu-Na/kafkaStudy development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카프카 Docs&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kafka.apache.org/documentation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kafka.apache.org/documentation/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1705555395513&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Apache Kafka&quot; data-og-description=&quot;Apache Kafka: A Distributed Streaming Platform.&quot; data-og-host=&quot;kafka.apache.org&quot; data-og-source-url=&quot;https://kafka.apache.org/documentation/&quot; data-og-url=&quot;https://kafka.apache.org/documentation/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/M11z0/hyU8TpRGNv/xpB0WRJq8hh1LBT5gqaDcK/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://kafka.apache.org/documentation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kafka.apache.org/documentation/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/M11z0/hyU8TpRGNv/xpB0WRJq8hh1LBT5gqaDcK/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Apache Kafka&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Apache Kafka: A Distributed Streaming Platform.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kafka.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/DevOps</category>
      <category>apache</category>
      <category>backend</category>
      <category>big data</category>
      <category>KAFKA</category>
      <category>개발자</category>
      <category>링크드인</category>
      <category>백엔드</category>
      <category>아파치</category>
      <category>아파치 카프카</category>
      <category>카프카</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/26</guid>
      <comments>https://djlife.tistory.com/26#entry26comment</comments>
      <pubDate>Fri, 17 Nov 2023 14:59:47 +0900</pubDate>
    </item>
    <item>
      <title>Slack , Google  spreadsheet  활용하여 업무 효율성 높이는 방법  </title>
      <link>https://djlife.tistory.com/25</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image001.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X5fEM/btszlZ1AMfx/R6oTg8NtWRneeRMPKgszuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X5fEM/btszlZ1AMfx/R6oTg8NtWRneeRMPKgszuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X5fEM/btszlZ1AMfx/R6oTg8NtWRneeRMPKgszuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX5fEM%2FbtszlZ1AMfx%2FR6oTg8NtWRneeRMPKgszuK%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;700&quot; height=&quot;287&quot; data-filename=&quot;image001.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일을 하다보면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이력 관리에 중요성을 정말 많이 깨닫게 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;보고용 자료를 만들 경우에도 전에 일하던 사람 업무를 이어 받을 경우에도.. 유지보수 할 때도 마찬가지다  &lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;분명 작성 당시에는 번거로움이 있을 순 있어도 필요한 시점에 이력이 없으면 입이 대빨 튀어 나오게 된다  &amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;
&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;기획자분들이 개발자분들에게 전달할 때&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;&lt;b&gt;구글 스크립트와 슬랙을 엮어보면 어떨까?&lt;/b&gt; 하고 간단하게 만들어 보았다  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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;1. 슬랙 워크스페이스 개설 , 채널 개설&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 슬랙 app 준비(&lt;b&gt;추천&lt;/b&gt;) or &lt;span style=&quot;background-color: #ffffff; color: #111111; text-align: start;&quot;&gt;Incoming Webhook (필자는 슬랙 app을 추천한다 이유는&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #111111; text-align: start;&quot;&gt;인커밍 웹훅은 퇴사하면 끊어져버리는 경우가 생길 수 있으므로..)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #111111; text-align: start;&quot;&gt;3. 구글 시트 준비&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #111111; text-align: start;&quot;&gt;4. 구글 스크립트 작성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #111111; text-align: start;&quot;&gt;5. 확인&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;a href=&quot;https://api.slack.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://api.slack.com/&lt;/a&gt; 에서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;슬랙 app을 만들 수 있다.&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;간단하게 정보 입력 후 Incoming Webhooks 메뉴 진입 후 활성화 하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면 하단에 &lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;Add New Webhook to Workspace 버튼을 클릭 하여&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;웹 훅을 받을 채널을 선택하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;이후에 url을 카피해서 메모해두고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;821&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch5JGn/btszsDXITxI/lKsXCMY9UAaoGI2cEKkjpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch5JGn/btszsDXITxI/lKsXCMY9UAaoGI2cEKkjpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch5JGn/btszsDXITxI/lKsXCMY9UAaoGI2cEKkjpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch5JGn%2FbtszsDXITxI%2FlKsXCMY9UAaoGI2cEKkjpK%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;1206&quot; height=&quot;821&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;821&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글 시트로 들어가서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상단 탭에 확장프로그램 - Apps Script 클릭&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1648&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bErqFi/btszwblFf8M/OtNpHECXeWZ8gzc38VGgd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bErqFi/btszwblFf8M/OtNpHECXeWZ8gzc38VGgd0/img.png&quot; data-alt=&quot;구글 시트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bErqFi/btszwblFf8M/OtNpHECXeWZ8gzc38VGgd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbErqFi%2FbtszwblFf8M%2FOtNpHECXeWZ8gzc38VGgd0%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;1648&quot; height=&quot;320&quot; data-origin-width=&quot;1648&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;구글 시트&lt;/figcaption&gt;
&lt;/figure&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;sendSlackMessageIfEmptyEColumn 함수는&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;dailyReport 함수는 트리거를 이용하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일 아침 10시에 집계하여 자동으로 슬랙 채널에 전송해주는 함수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698678637554&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Slack 웹훅 URL 설정
const slackWebhookUrl = &quot;&quot;;

function sendSlackMessageIfEmptyEColumn() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName(&quot;일정관리&quot;);

  // D5:D1000 범위에서 값 확인
  var dataRange = sheet.getRange(&quot;D5:D1000&quot;);
  var dataValues = dataRange.getValues();
  var lastRow = dataRange.getLastRow();

  // Slack 메시지 전송 함수
  function sendSlackMessage(m0,m1,m2,m3) {
    var currentTime = Math.floor(new Date().getTime() / 1000);
    var payload = {
        &quot;channel&quot;: &quot;ABCDEBF1&quot;,
        &quot;attachments&quot;: 
        [
            {
                &quot;mrkdwn_in&quot;: &quot;&quot;,
                &quot;color&quot;: &quot;#36a64f&quot;,
                &quot;pretext&quot;: &quot;[&quot; + m0 + &quot;] 업무를 확인해주세요.&quot;,
                &quot;title&quot;: &quot;구글 시트 확인하기&quot;,
                &quot;title_link&quot;: &quot;타이틀 선택 시 이동 될 링크&quot;,
                &quot;text&quot;: m1 + &quot;\n담당자는 일자를 입력해주세요.\n검수자는 최종 확인 후 상태 값을 완료 또는 반려로 변경해주세요.&quot;,
                &quot;fields&quot;: 
                [
                    {
                        &quot;title&quot;: &quot;담당자&quot;,
                        &quot;value&quot;: m2,
                        &quot;short&quot;: true
                    },
                    {
                        &quot;title&quot;: &quot;검수자&quot;,
                        &quot;value&quot;: m3,
                        &quot;short&quot;: true
                    }
                ],
                &quot;thumb_url&quot;: &quot;http://placekitten.com/g/200/200&quot;,
                &quot;footer&quot;: &quot;footer&quot;,
                &quot;footer_icon&quot;: &quot;https://platform.slack-edge.com/img/default_application_icon.png&quot;,
                &quot;ts&quot;: currentTime
            }
        ]
    };
    var options = {
      method: &quot;post&quot;,
      payload: JSON.stringify(payload),
      contentType: &quot;application/json&quot;
    };
    UrlFetchApp.fetch(slackWebhookUrl, options);
  }

  // D5:D1000 범위 반복 및 E열 값 확인
  for (var i = 0; i &amp;lt; lastRow - 4; i++) {
    var cValue = sheet.getRange(5 + i, 3).getValue();
    var dValue = dataValues[i][0];
    var eValue = sheet.getRange(5 + i, 5).getValue();
    var gValue = sheet.getRange(5 + i, 7).getValue();
    var hValue = sheet.getRange(5 + i, 8).getValue();
    var lValue = sheet.getRange(5 + i, 11).getValue();

    Logger.log(&quot;lValue 값: &quot; + lValue);
     if (cValue !== &quot;&quot; &amp;amp;&amp;amp; dValue !== &quot;&quot; &amp;amp;&amp;amp; eValue !== &quot;&quot; &amp;amp;&amp;amp; lValue !== &quot; &amp;zwj;♂️ &amp;zwj;♀️&quot;) {
      sendSlackMessage(cValue,dValue,gValue,hValue);
      sheet.getRange(5 + i, 12).setValue(&quot; &amp;zwj;♂️ &amp;zwj;♀️&quot;);
    } else if (dValue === &quot;&quot; &amp;amp;&amp;amp; eValue === &quot;&quot; &amp;amp;&amp;amp; lastRow &amp;gt; 0) {
      break;
    }
  }
}


function dailyReport(){
  // 스프레드시트 및 시트 설정
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName(&quot;일정관리&quot;); // 시트 이름을 업데이트하세요.

  // D5:D1000 범위에서 값 확인
  var dataRange = sheet.getRange(&quot;D5:D1000&quot;);
  var lastRow = dataRange.getLastRow();

  // E열 및 K열에서 &quot;완료&quot;, &quot;보류&quot;, &quot;접수&quot;, &quot;반려&quot; 갯수를 세기 위한 변수 초기화
  var countCompletedE = 0;
  var countPendingE = 0;
  var countAcceptedE = 0;
  var countCompletedK = 0;
  var countRejectedK = 0;
  var forFlag = false;

  // D5:D1000 범위 반복 및 E열과 K열 값 확인
  for (var i = 0; i &amp;lt; lastRow - 4; i++) {
    var eValue = sheet.getRange(5 + i, 5).getValue(); // E열 값 가져오기
    var kValue = sheet.getRange(5 + i, 11).getValue(); // K열 값 가져오기

    if (eValue === &quot;완료&quot;) {
      countCompletedE++;
    } else if (eValue === &quot;보류&quot;) {
      countPendingE++;
    } else if (eValue === &quot;접수&quot;) {
      countAcceptedE++;
    }

    if (kValue === &quot;완료&quot;) {
      countCompletedK++;
    } else if (kValue === &quot;반려&quot;) {
      countRejectedK++;
    }

     if(eValue === &quot;&quot; &amp;amp;&amp;amp; kValue === &quot;&quot;){
      forFlag = true;
      break;
    }
  }

  if(forFlag){
    // to do  다음 행이 비어 있을 경우 처리
  
  }

  // Slack 메시지 생성
  var slackMessage = &quot;데일리 보고:\n담당자 확인 집계: 완료-&quot; + countCompletedE + &quot;, 보류-&quot; + countPendingE + &quot;, 접수-&quot; + countAcceptedE +
                     &quot;\n검토자 확인 집계: 완료-&quot; + countCompletedK + &quot;, 반려-&quot; + countRejectedK;

  // Slack 메시지 전송
  var payload = {
    &quot;channel&quot;: &quot;YOUR_CHANNEL_ID&quot;, // Slack 채널 ID를 업데이트하세요
    &quot;text&quot;: slackMessage
  };

  var options = {
    method: &quot;post&quot;,
    payload: JSON.stringify(payload),
    contentType: &quot;application/json&quot;
  };

  UrlFetchApp.fetch(slackWebhookUrl, options);
}&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/odHy7/btszlvGvkPd/okUKa2ByJunYaAepexQRuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/odHy7/btszlvGvkPd/okUKa2ByJunYaAepexQRuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/odHy7/btszlvGvkPd/okUKa2ByJunYaAepexQRuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FodHy7%2FbtszlvGvkPd%2FokUKa2ByJunYaAepexQRuK%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;718&quot; height=&quot;248&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #111111; text-align: start;&quot;&gt;Incoming Webhook 을 이용하게 된다면 이분이 잘 정리한거 같다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sonujung.com/slack-reminder-with-google-spread-sheets&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://sonujung.com/slack-reminder-with-google-spread-sheets&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698677654870&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;'구글 스프레드시트'로 '슬랙 리마인더 봇' 만들기&quot; data-og-description=&quot;모두가 고객과 직접 대화하기 식스샵에선 서비스 운영팀 분들 외에도 모든 구성원이 고객 상담 업무에 참여하고 있다. 이는 창업 초반 Wufoo의 공동 창업자 Kevin Hale이 ' How to build products users love '&quot; data-og-host=&quot;sonujung.com&quot; data-og-source-url=&quot;https://sonujung.com/slack-reminder-with-google-spread-sheets&quot; data-og-url=&quot;https://sonujung.com/slack-reminder-with-google-spread-sheets&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bhTogp/hyUkk4QY5N/D6fGICx4HBfQwNx027Ioek/img.jpg?width=1032&amp;amp;height=553&amp;amp;face=0_0_1032_553&quot;&gt;&lt;a href=&quot;https://sonujung.com/slack-reminder-with-google-spread-sheets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sonujung.com/slack-reminder-with-google-spread-sheets&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bhTogp/hyUkk4QY5N/D6fGICx4HBfQwNx027Ioek/img.jpg?width=1032&amp;amp;height=553&amp;amp;face=0_0_1032_553');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;'구글 스프레드시트'로 '슬랙 리마인더 봇' 만들기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;모두가 고객과 직접 대화하기 식스샵에선 서비스 운영팀 분들 외에도 모든 구성원이 고객 상담 업무에 참여하고 있다. 이는 창업 초반 Wufoo의 공동 창업자 Kevin Hale이 ' How to build products users love '&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sonujung.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://techblog.lotteon.com/%EB%A1%AF%EB%8D%B0e%EC%BB%A4%EB%A8%B8%EC%8A%A4-slack-bot-%ED%99%9C%EC%9A%A9%EA%B8%B0-273be23489ed&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://techblog.lotteon.com/%EB%A1%AF%EB%8D%B0e%EC%BB%A4%EB%A8%B8%EC%8A%A4-slack-bot-%ED%99%9C%EC%9A%A9%EA%B8%B0-273be23489ed&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698677732404&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Slack bot을 통한 업무 활용스토리 #1&quot; data-og-description=&quot;Slack 도입이 가져온 롯데e커머스의 변화  &quot; data-og-host=&quot;techblog.lotteon.com&quot; data-og-source-url=&quot;https://techblog.lotteon.com/%EB%A1%AF%EB%8D%B0e%EC%BB%A4%EB%A8%B8%EC%8A%A4-slack-bot-%ED%99%9C%EC%9A%A9%EA%B8%B0-273be23489ed&quot; data-og-url=&quot;https://techblog.lotteon.com/%EB%A1%AF%EB%8D%B0e%EC%BB%A4%EB%A8%B8%EC%8A%A4-slack-bot-%ED%99%9C%EC%9A%A9%EA%B8%B0-273be23489ed&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cLU1SV/hyUnJBQHZ7/6K8fJcwh7kmxkHapSh1JnK/img.png?width=1142&amp;amp;height=397&amp;amp;face=0_0_1142_397&quot;&gt;&lt;a href=&quot;https://techblog.lotteon.com/%EB%A1%AF%EB%8D%B0e%EC%BB%A4%EB%A8%B8%EC%8A%A4-slack-bot-%ED%99%9C%EC%9A%A9%EA%B8%B0-273be23489ed&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techblog.lotteon.com/%EB%A1%AF%EB%8D%B0e%EC%BB%A4%EB%A8%B8%EC%8A%A4-slack-bot-%ED%99%9C%EC%9A%A9%EA%B8%B0-273be23489ed&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cLU1SV/hyUnJBQHZ7/6K8fJcwh7kmxkHapSh1JnK/img.png?width=1142&amp;amp;height=397&amp;amp;face=0_0_1142_397');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Slack bot을 통한 업무 활용스토리 #1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Slack 도입이 가져온 롯데e커머스의 변화  &lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techblog.lotteon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://api.slack.com/reference/messaging/attachments&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://api.slack.com/reference/messaging/attachments&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698678018691&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Reference: Secondary message attachments&quot; data-og-description=&quot;Another way to attach content to messages is the old attachments system. We prefer Block Kit now.&quot; data-og-host=&quot;api.slack.com&quot; data-og-source-url=&quot;https://api.slack.com/reference/messaging/attachments&quot; data-og-url=&quot;https://slack.com/reference/messaging/attachments&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nKZaz/hyUnTxIx6F/rZvNhXTu9qFIpyFOw1kLvK/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200,https://scrap.kakaocdn.net/dn/dHqHnH/hyUnV3nrBV/PMSA52VZEdMZ5dZOOdihgK/img.png?width=1680&amp;amp;height=650&amp;amp;face=0_0_1680_650&quot;&gt;&lt;a href=&quot;https://api.slack.com/reference/messaging/attachments&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://api.slack.com/reference/messaging/attachments&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nKZaz/hyUnTxIx6F/rZvNhXTu9qFIpyFOw1kLvK/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200,https://scrap.kakaocdn.net/dn/dHqHnH/hyUnV3nrBV/PMSA52VZEdMZ5dZOOdihgK/img.png?width=1680&amp;amp;height=650&amp;amp;face=0_0_1680_650');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Reference: Secondary message attachments&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Another way to attach content to messages is the old attachments system. We prefer Block Kit now.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;api.slack.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Tool</category>
      <category>google spreadsheet</category>
      <category>Incoming Webhook</category>
      <category>slack</category>
      <category>구글</category>
      <category>구글 시트</category>
      <category>구글 시트를 이용해서 리마인더 만들기</category>
      <category>슬랙</category>
      <category>이모지</category>
      <category>협업도구</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/25</guid>
      <comments>https://djlife.tistory.com/25#entry25comment</comments>
      <pubDate>Tue, 31 Oct 2023 00:12:17 +0900</pubDate>
    </item>
    <item>
      <title>스프링 부트 카카오 로그인 API 기능 추가하기   </title>
      <link>https://djlife.tistory.com/24</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-10-22 220301.png&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;797&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqljZN/btsyU51txIa/w4ZBdcgFp6XB7E1J86503k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqljZN/btsyU51txIa/w4ZBdcgFp6XB7E1J86503k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqljZN/btsyU51txIa/w4ZBdcgFp6XB7E1J86503k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqljZN%2FbtsyU51txIa%2Fw4ZBdcgFp6XB7E1J86503k%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;772&quot; height=&quot;797&quot; data-filename=&quot;화면 캡처 2023-10-22 220301.png&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;797&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;공모전을 진행하면서&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;카카오 API를 이용하면 가산점이 있었기에  &lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;만들고 있는 기능 중 회원가입하는 부분이 있었고&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;카카오는 많은 사용자들이 이용중인 플랫폼이기에 사용자 측면에서 편의성을 주고자&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;카카오 로그인 기능을 추가하게 되었다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;당시 api 서버 환경은&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;jdk 17&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;spring 6.0.8&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;spring boot 3.0.6&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;jpa&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;security&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;oauth2&lt;/s&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;시큐리티를 사용하고 있으니&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;oauth2를 이용하여 로그인까지 연결 시키고 싶었는데&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 방법대로는 내가 원하는 대로 흘러가지 않아서 결국에는 api식을로 개발했던 것 같네 지금 코드를 보니  &lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;시간이 더 많았으면 스프링 환경을 더 봐서 코드를 깔끔하게 할 수 있었을 것 같은데&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;조금 아쉬움이 남네&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;진행상황&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1.카카오 디벨로퍼에서 카카오 로그인 프로세스 이해하기&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. oauth2 개념 이해하기&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. api vs &lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;security oauth2&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이슈 &amp;amp; 고민 및 해결&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프론트에서 카카오 로그인 시 백엔드로 통신하고 인증/인가&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;확인 후 jwt 토큰 내려주는 프로세스로 개발하고 싶었는데&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;api 서버에 oauth2까지 같이 사용하고 있다보니&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;필터에 불필요 예외처리 코드가 너무 늘어나는 것 같아서&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;카카오 로그인 api로 분리하게 되었다.  &lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 카카오 로그인 이해하기&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://developers.kakao.com/docs/latest/ko/kakaologin/common&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.kakao.com/docs/latest/ko/kakaologin/common&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697981402206&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Kakao Developers&quot; data-og-description=&quot;카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.&quot; data-og-host=&quot;developers.kakao.com&quot; data-og-source-url=&quot;https://developers.kakao.com/docs/latest/ko/kakaologin/common&quot; data-og-url=&quot;https://developers.kakao.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bjUul3/hyUkge6szi/Ul76wzokkluJvPAzl5Ker1/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/jwGb8/hyUkfAuZwK/JNR4TaNADOdPsVb7VFiWuK/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000,https://scrap.kakaocdn.net/dn/dXgJBD/hyUkgTH27k/MDBJBsC3La6kP1hqD4gaNK/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000&quot;&gt;&lt;a href=&quot;https://developers.kakao.com/docs/latest/ko/kakaologin/common&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers.kakao.com/docs/latest/ko/kakaologin/common&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bjUul3/hyUkge6szi/Ul76wzokkluJvPAzl5Ker1/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/jwGb8/hyUkfAuZwK/JNR4TaNADOdPsVb7VFiWuK/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000,https://scrap.kakaocdn.net/dn/dXgJBD/hyUkgTH27k/MDBJBsC3La6kP1hqD4gaNK/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Kakao Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers.kakao.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 카카오 로그인 설정하기&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://developers.kakao.com/docs/latest/ko/kakaologin/prerequisite&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.kakao.com/docs/latest/ko/kakaologin/prerequisite&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697981412064&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Kakao Developers&quot; data-og-description=&quot;카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.&quot; data-og-host=&quot;developers.kakao.com&quot; data-og-source-url=&quot;https://developers.kakao.com/docs/latest/ko/kakaologin/prerequisite&quot; data-og-url=&quot;https://developers.kakao.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/byHmbd/hyUj7WLP17/M8fSkN91RsIook6zD6REIK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/gBmHw/hyUki430fP/NKKtwYEecviPOR6k51rB3K/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000,https://scrap.kakaocdn.net/dn/uDXTE/hyUkiDZA7o/CPdWkVO9xMt6XuQBCvqX20/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000&quot;&gt;&lt;a href=&quot;https://developers.kakao.com/docs/latest/ko/kakaologin/prerequisite&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers.kakao.com/docs/latest/ko/kakaologin/prerequisite&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/byHmbd/hyUj7WLP17/M8fSkN91RsIook6zD6REIK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/gBmHw/hyUki430fP/NKKtwYEecviPOR6k51rB3K/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000,https://scrap.kakaocdn.net/dn/uDXTE/hyUkiDZA7o/CPdWkVO9xMt6XuQBCvqX20/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Kakao Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers.kakao.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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. 인증&amp;amp;인가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.gmarket.com/45&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;&lt;b&gt;https://dev.gmarket.com/45&lt;/b&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697981844008&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;인증/인가는 어디에 어떻게 구현해야 할까?&quot; data-og-description=&quot;안녕하세요 Post-tx &amp;amp; Accounting팀 권우석입니다. 최근 온보딩 프로젝트를 함께했던 Shopping Service API팀의 김도훈님의 제안으로 회원가입/로그인 API를 간단하게 구현하는 토이 프로젝트를 진행하고 &quot; data-og-host=&quot;dev.gmarket.com&quot; data-og-source-url=&quot;https://dev.gmarket.com/45&quot; data-og-url=&quot;https://dev.gmarket.com/45&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/SZPRM/hyUgMmqvdm/YBkxCrfEQek8HIZfm7ZJn0/img.gif?width=500&amp;amp;height=279&amp;amp;face=177_8_265_104,https://scrap.kakaocdn.net/dn/bi9XWG/hyUkh59Z1L/gF7OVoZFrbbDY9t4slZUJK/img.gif?width=500&amp;amp;height=279&amp;amp;face=177_8_265_104,https://scrap.kakaocdn.net/dn/dSe7ro/hyUgStpZn4/Mtp7SwdqEKuhoov3VXcQxk/img.png?width=2723&amp;amp;height=1536&amp;amp;face=0_0_2723_1536&quot;&gt;&lt;a href=&quot;https://dev.gmarket.com/45&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.gmarket.com/45&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/SZPRM/hyUgMmqvdm/YBkxCrfEQek8HIZfm7ZJn0/img.gif?width=500&amp;amp;height=279&amp;amp;face=177_8_265_104,https://scrap.kakaocdn.net/dn/bi9XWG/hyUkh59Z1L/gF7OVoZFrbbDY9t4slZUJK/img.gif?width=500&amp;amp;height=279&amp;amp;face=177_8_265_104,https://scrap.kakaocdn.net/dn/dSe7ro/hyUgStpZn4/Mtp7SwdqEKuhoov3VXcQxk/img.png?width=2723&amp;amp;height=1536&amp;amp;face=0_0_2723_1536');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;인증/인가는 어디에 어떻게 구현해야 할까?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 Post-tx &amp;amp; Accounting팀 권우석입니다. 최근 온보딩 프로젝트를 함께했던 Shopping Service API팀의 김도훈님의 제안으로 회원가입/로그인 API를 간단하게 구현하는 토이 프로젝트를 진행하고&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.gmarket.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; 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;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 사용한 코드 github&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/Nadry&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/DongJu-Na/Nadry&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697982628729&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - DongJu-Na/Nadry: 여행&quot; data-og-description=&quot;여행. Contribute to DongJu-Na/Nadry development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/DongJu-Na/Nadry&quot; data-og-url=&quot;https://github.com/DongJu-Na/Nadry&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sIkwx/hyUkfgc3Mt/jRjQZ13Iiv8RvVP4rBimIk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/Nadry&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/DongJu-Na/Nadry&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sIkwx/hyUkfgc3Mt/jRjQZ13Iiv8RvVP4rBimIk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - DongJu-Na/Nadry: 여행&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;여행. Contribute to DongJu-Na/Nadry development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TO DO List&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 스프링 환경 공부&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 네이버,구글,github login 기능 추가해보기&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example Code&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;카카오 로그인 api 예제 코드&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 컨트롤러&lt;/p&gt;
&lt;pre id=&quot;code_1697979466737&quot; class=&quot;java&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.nadeul.ndj.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.nadeul.ndj.dto.ApiResponse;
import com.nadeul.ndj.dto.KakaoDto;
import com.nadeul.ndj.dto.MemberDto;
import com.nadeul.ndj.service.KakaoApiService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;

@Tag(name = &quot;KakaoService&quot;, description = &quot;카카오 API&quot;)
@RequestMapping(&quot;/api/v1/kakao&quot;)
@RequiredArgsConstructor
@RestController
public class KakaoApiController&amp;lt;T&amp;gt; {
	
	private final KakaoApiService&amp;lt;T&amp;gt; service;
	
	@PostMapping(&quot;/authenticate&quot;)
	@Operation(summary = &quot;카카오 로그인&quot;, description = &quot;카카오 계정으로 로그인&quot;)
    public ResponseEntity&amp;lt;ApiResponse&amp;lt;MemberDto&amp;gt;&amp;gt; kakaoAuthenticate(@RequestBody KakaoDto request) {
        return ResponseEntity.ok(service.kakaoAuthenticate(request));
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 서비스&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;@value 어노테이션 부분에는&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;카카오에서 발급받은 클라이언트 id와&amp;nbsp; 설정해놓은 redirect url 할당해서 사용하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1697979466740&quot; class=&quot;java&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.nadeul.ndj.service;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nadeul.ndj.dto.ApiResponse;
import com.nadeul.ndj.dto.KakaoDto;
import com.nadeul.ndj.dto.MemberDto;
import com.nadeul.ndj.entity.Member;
import com.nadeul.ndj.entity.Token;
import com.nadeul.ndj.enums.ApiResponseEnum;
import com.nadeul.ndj.model.Role;
import com.nadeul.ndj.model.TokenType;
import com.nadeul.ndj.repository.MemberRepository;
import com.nadeul.ndj.repository.TokenRepository;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class KakaoApiService&amp;lt;T&amp;gt; {
	
	private final MemberRepository memberRepository;
    private final TokenRepository tokenRepository;
    private final JwtService jwtService;
    
    @Value(&quot;${spring.security.oauth2.client.registration.kakao.client-id}&quot;)
    private String CLIENT_ID;
    @Value(&quot;${spring.security.oauth2.client.registration.kakao.redirect-uri}&quot;)
    private String REDIRECT_URI;
    
		
      @SuppressWarnings(&quot;unchecked&quot;)
	  public ApiResponse&amp;lt;MemberDto&amp;gt; kakaoAuthenticate(KakaoDto request) {
		  
    	  String kakaoAccessToken = getKaKaoAccessToken(request.getCode());
    	  HashMap&amp;lt;String, Object&amp;gt; kakaoInfo = getUserKakaoInfo(kakaoAccessToken);
    	  
    	  
  		  String email = (String) kakaoInfo.get(&quot;email&quot;);
  		  
  		  Optional&amp;lt;Member&amp;gt; existingMember = memberRepository.findByEmail(email);
  		  
  		if(existingMember.isPresent()) {
  			Member member = Member.builder()
  				  .memId(existingMember.get().getMemId())
  				  .name(kakaoInfo.get(&quot;name&quot;).toString())
  		          .email(kakaoInfo.get(&quot;email&quot;).toString())
  		          .profileUrl(kakaoInfo.get(&quot;profileUrl&quot;).toString())
  		          .build();
  			
  			var savedUser = memberRepository.save(member);
  			
  			String jwtToken = jwtService.generateToken(existingMember.get());
        	String refreshToken = jwtService.generateRefreshToken(existingMember.get());
        	List&amp;lt;Token&amp;gt; validUserTokens = tokenRepository.findAllValidTokenByUser(existingMember.get().getMemId());
      	    validUserTokens.forEach(token -&amp;gt; {
      	      token.setExpired(true);
      	      token.setRevoked(true);
      	    });
      	    tokenRepository.saveAll(validUserTokens);
      	    
      	    Token token = Token.builder()
    	            .member(existingMember.get())
    	            .token(jwtToken)
    	            .tokenType(TokenType.BEARER)
    	            .expired(false)
    	            .revoked(false)
    	            .build();
    	        tokenRepository.save(token);   
    	    
    	     MemberDto memberDto = new MemberDto();
  			  memberDto.setMemId(existingMember.get().getMemId());
  			  memberDto.setName(existingMember.get().getName());
  			  memberDto.setEmail(existingMember.get().getEmail());
  			  memberDto.setPassword(existingMember.get().getPassword());
  			  memberDto.setBirthDay(existingMember.get().getBirthDay());
  			  memberDto.setRole(existingMember.get().getRole());
  			  memberDto.setProfileUrl(existingMember.get().getProfileUrl());
  			  
  			return ApiResponse.successResponse(ApiResponseEnum.SUCCESS,memberDto,jwtToken,refreshToken);
  		}else {
  			 Member member = Member.builder()
  				
  		          .name(kakaoInfo.get(&quot;name&quot;).toString())
  		          .email(kakaoInfo.get(&quot;email&quot;).toString())
  		          .password(null)
  		          .role(Role.USER)
  		          .birthDay(null)
  		          .profileUrl(kakaoInfo.get(&quot;profileUrl&quot;).toString())  
  		          .build();
  		      var savedUser = memberRepository.save(member);
  		      var jwtToken = jwtService.generateToken(member);
  		      var refreshToken = jwtService.generateRefreshToken(member);
  		      
  		      MemberDto memberDto = new MemberDto();
			  memberDto.setMemId(member.getMemId());
			  memberDto.setName(member.getName());
			  memberDto.setEmail(member.getEmail());
			  memberDto.setPassword(member.getPassword());
			  memberDto.setBirthDay(member.getBirthDay());
			  memberDto.setRole(member.getRole());
			  memberDto.setProfileUrl(member.getProfileUrl());
  		      
  		    return ApiResponse.successResponse(ApiResponseEnum.SUCCESS,memberDto,jwtToken,refreshToken);
  		}
  		
	  }
      
      
      public String getKaKaoAccessToken(String code) {

    	    String access_Token = &quot;&quot;;
    	    String refresh_Token = &quot;&quot;;
    	    String reqURL = &quot;https://kauth.kakao.com/oauth/token&quot;;

    	    try {
    	        URL url = new URL(reqURL);
    	        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

    	        conn.setRequestMethod(&quot;POST&quot;);
    	        conn.setDoOutput(true);

    	        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
    	        StringBuilder sb = new StringBuilder();
    	        sb.append(&quot;grant_type=authorization_code&quot;);
    	        sb.append(&quot;&amp;amp;client_id=&quot; + CLIENT_ID);
    	        sb.append(&quot;&amp;amp;redirect_uri=&quot; + REDIRECT_URI);
    	        sb.append(&quot;&amp;amp;code=&quot; + code);
    	        bw.write(sb.toString());
    	        bw.flush();

    	        int responseCode = conn.getResponseCode();
    	        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    	        String line = &quot;&quot;;
    	        String result = &quot;&quot;;

    	        while ((line = br.readLine()) != null) {
    	            result += line;
    	        }
    	        
    	        ObjectMapper objectMapper = new ObjectMapper();
    	        JsonNode rootNode = objectMapper.readTree(result);
    	        
    	        access_Token = rootNode.get(&quot;access_token&quot;).asText();
    	        refresh_Token = rootNode.get(&quot;refresh_token&quot;).asText();

    	        br.close();
    	        bw.close();
    	    } catch (IOException e) {
    	        e.printStackTrace();
    	    }

    	    return access_Token;
    	}
      
      public HashMap&amp;lt;String, Object&amp;gt; getUserKakaoInfo(String access_Token) {

    	    HashMap&amp;lt;String, Object&amp;gt; userInfo = new HashMap&amp;lt;String, Object&amp;gt;();
    	    String reqURL = &quot;https://kapi.kakao.com/v2/user/me&quot;;
    	    try {
    	        URL url = new URL(reqURL);
    	        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    	        conn.setRequestMethod(&quot;GET&quot;);

    	        conn.setRequestProperty(&quot;Authorization&quot;, &quot;Bearer &quot; + access_Token);

    	        int responseCode = conn.getResponseCode();

    	        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

    	        String line = &quot;&quot;;
    	        String result = &quot;&quot;;

    	        while ((line = br.readLine()) != null) {
    	            result += line;
    	        }

    	        ObjectMapper objectMapper = new ObjectMapper();
    	        JsonNode rootNode = objectMapper.readTree(result.toString());

    	        String id = rootNode.path(&quot;id&quot;).asText();

    	        JsonNode propertiesNode = rootNode.path(&quot;properties&quot;);
    	        JsonNode kakaoAccountNode = rootNode.path(&quot;kakao_account&quot;);

    	        String nickname = propertiesNode.path(&quot;nickname&quot;).asText();
    	        if (kakaoAccountNode.has(&quot;email&quot;)) {
    	            String email = kakaoAccountNode.path(&quot;email&quot;).asText();
    	            userInfo.put(&quot;email&quot;, email);
    	        }

    	        userInfo.put(&quot;name&quot;, nickname);
    	        userInfo.put(&quot;id&quot;, id);
    	        userInfo.put(&quot;profileUrl&quot;, propertiesNode.path(&quot;thumbnail_image&quot;).asText());
    	        userInfo.put(&quot;role&quot;, Role.USER);

    	    } catch (IOException e) {
    	        e.printStackTrace();
    	    }
    	    return userInfo;
    	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>kakao</category>
      <category>kakao login</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>스프링부트</category>
      <category>카카오 디벨로퍼</category>
      <category>카카오 로그인 api</category>
      <category>카카오 로그인 api 예제 코드</category>
      <category>카카오로그인</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/24</guid>
      <comments>https://djlife.tistory.com/24#entry24comment</comments>
      <pubDate>Sun, 22 Oct 2023 22:51:13 +0900</pubDate>
    </item>
    <item>
      <title>vue.js 카카오맵 마커가 초기화 안되는 이유가 뭘까?  </title>
      <link>https://djlife.tistory.com/23</link>
      <description>&lt;pre id=&quot;code_1695543110933&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;flex flex-col my-10&quot;&amp;gt;
    &amp;lt;h2 class=&quot;px-5 mb-3 text-lg font-semibold&quot;&amp;gt;주변을 둘러 보세요&amp;lt;/h2&amp;gt;
    &amp;lt;div id=&quot;map&quot; class=&quot;w-full h-[500px]&quot;&amp;gt;
      &amp;lt;!-- input --&amp;gt;
      &amp;lt;div class=&quot;absolute z-[99] p-3 w-full&quot;&amp;gt;
        &amp;lt;div class=&quot;flex items-center w-full p-3 bg-white rounded-md shadow-md&quot;&amp;gt;
          &amp;lt;i class=&quot;mr-2 text-xl las la-search text-zinc-400&quot;&amp;gt;&amp;lt;/i&amp;gt;
            &amp;lt;input  
                v-model=&quot;searchWord&quot; 
                @keyup.enter=&quot;onEnter&quot;
                type=&quot;text&quot; 
                placeholder=&quot;지금, 경주를 검색해보세요!&quot; 
            /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;style&amp;gt;
    .wrap {position: absolute;left: 0;bottom: 40px;width: 288px;height: 132px;margin-left: -144px;text-align: left;overflow: hidden;font-size: 12px;font-family: 'Malgun Gothic', dotum, '돋움', sans-serif;line-height: 1.5;}
    .wrap * {padding: 0;margin: 0;}
    .wrap .info {width: 286px;height: 120px;border-radius: 5px;border-bottom: 2px solid #ccc;border-right: 1px solid #ccc;overflow: hidden;background: #fff;}
    .wrap .info:nth-child(1) {border: 0;box-shadow: 0px 1px 2px #888;}
    .info .title {padding: 5px 0 0 10px;height: 30px;background: #eee;border-bottom: 1px solid #ddd;font-size: 18px;font-weight: bold;}
    .info .close {position: absolute;top: 10px;right: 10px;color: #888;width: 17px;height: 17px;background: url('https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/overlay_close.png');}
    .info .close:hover {cursor: pointer;}
    .info .body {position: relative;overflow: hidden;}
    .info .desc {position: relative;margin: 13px 0 0 90px;height: 75px;}
    .desc .ellipsis {overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}
    .desc .jibun {font-size: 11px;color: #888;margin-top: -2px;}
    .info .img {position: absolute;top: 6px;left: 5px;width: 73px;height: 71px;border: 1px solid #ddd;color: #888;overflow: hidden;}
    .info:after {content: '';position: absolute;margin-left: -12px;left: 50%;bottom: 0;width: 22px;height: 12px;background: url('https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/vertex_white.png')}
    .info .link {color: #5085BB;}
&amp;lt;/style&amp;gt;

&amp;lt;script setup&amp;gt;
import { onMounted, ref } from 'vue';
import { searchTrip } from '@/api';

const searchWord = ref('');

let map,displayMarkers = [];

const submit = async () =&amp;gt; {
  if (!searchWord.value) {
    alert('검색어를 입력하세요.');
    return;
  }

  try {
    const payload = {
      numOfRows: 10,
      pageNo: 1,
      MobileOS: 'ETC',
      MobileApp: 'AppTest',
      _type: 'json',
      listYN: 'Y',
      contentTypeId: '',
      arrange: 'A',
      areaCode: '',
      sigunguCode: '',
      cat1: '',
      cat2: '',
      cat3: '',
      keyword: searchWord.value,
    };

     await searchTrip(payload).then((result)=&amp;gt;{
    const {status, data: {response: { body }}} = result;
      console.log(this.displayMarkers);
            for (var i = 0; i &amp;lt; this.displayMarkers.length; i++) {
                this.displayMarkers[i].setMap(null);
            }
            this.displayMarkers.splice(0, this.displayMarkers.length);
          
        if (status === 200 &amp;amp;&amp;amp; body &amp;amp;&amp;amp; body.items.item.length &amp;gt; 0) {
            map.relayout();

            body.items.item.forEach(item =&amp;gt; {
              let kakaoPos = new kakao.maps.LatLng(item.mapy, item.mapx);
              let marker = new kakao.maps.Marker({
                map: map,
                position: kakaoPos,
                title: item.title,
                clickable: true
              });

              console.log(&quot;위치 잘 찍히니? 네 =&amp;gt; &quot; + marker.getTitle());

              let imageSrc = &quot;http://t1.daumcdn.net/localimg/localimages/07/mapapidoc/markerStar.png&quot;;
              let imageSize = new kakao.maps.Size(37, 45);
              let imageOption = { offset: new kakao.maps.Point(17, 40) };

              let markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption);
              let markerPosition = marker.getPosition();

              marker = new kakao.maps.Marker({
                position: markerPosition,
                // image: markerImage
              });

              marker.setMap(map);
              let imgUrl = (item.firstimage === null || item.firstimage === &quot;&quot;  ? &quot;/svg/empty_face.svg&quot; : item.firstimage);

              let closeOverlay = () =&amp;gt;{
                console.log(&quot;call ?&quot;);
              }

              let contentHtml =  `&amp;lt;div class=&quot;wrap&quot;&amp;gt;
                                    &amp;lt;div class=&quot;info&quot;&amp;gt;
                                      &amp;lt;div class=&quot;title&quot;&amp;gt;
                                        ${item.title}
                                        &amp;lt;div class=&quot;close&quot; onclick=&quot;closeOverlay&quot; title=&quot;닫기&quot;&amp;gt;&amp;lt;/div&amp;gt;
                                      &amp;lt;/div&amp;gt;
                                      &amp;lt;div class=&quot;body&quot;&amp;gt;
                                        &amp;lt;div class=&quot;img&quot;&amp;gt;
                                          &amp;lt;img src=${imgUrl} width=&quot;73&quot; height=&quot;70&quot;&amp;gt;
                                        &amp;lt;/div&amp;gt;
                                        &amp;lt;div class=&quot;desc&quot;&amp;gt;
                                          &amp;lt;div class=&quot;ellipsis&quot;&amp;gt;&amp;lt;/div&amp;gt;
                                          &amp;lt;div class=&quot;jibun ellipsis&quot;&amp;gt;${item.addr1 + &quot; &quot; + item.addr2}&amp;lt;/div&amp;gt;
                                          &amp;lt;div&amp;gt;&amp;lt;a href=${&quot;/trips/&quot; + item.contentid + &quot;/&quot; +item.contenttypeid} class=&quot;link&quot;&amp;gt;상세보기&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
                                        &amp;lt;/div&amp;gt;
                                      &amp;lt;/div&amp;gt;
                                    &amp;lt;/div&amp;gt;
                                  &amp;lt;/div&amp;gt;
                                `;
              
                let overlay = new kakao.maps.CustomOverlay({
                    content: contentHtml,
                    map: map,
                    position: marker.getPosition()       
                });

          
                kakao.maps.event.addListener(marker, 'click', function() {
                    overlay.setMap(map);
                });
                
                this.displayMarkers.push(marker);
            });

            let firstSearchMapPos = new kakao.maps.LatLng(body.items.item[0].mapy , body.items.item[0].mapx);
            map.setCenter(firstSearchMapPos);

        }else{
          alert(&quot;검색 결과가 없습니다.&quot;);
        }
    });
        
  } catch (error) {
    console.log(error);
  }
};

const onEnter = () =&amp;gt; {
  submit(searchWord.value);
};

const getLocation = () =&amp;gt; {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition((position) =&amp;gt; {
      const myPosition = new kakao.maps.LatLng(position.coords.latitude, position.coords.longitude);
      map.setCenter(myPosition);

      const marker = new kakao.maps.Marker({
        position: myPosition,
        map: map,
      });
    });
  } else {
    console.log('getLocation error');
  }
};

const loadMap = () =&amp;gt; {
  const container = document.getElementById('map');
  const options = {
    center: new kakao.maps.LatLng(33.450701, 126.570667),
    level: 7,
  };
  map = new kakao.maps.Map(container, options);

  getLocation();
};

onMounted(() =&amp;gt; {
  if (window.kakao &amp;amp;&amp;amp; window.kakao.maps) {
    loadMap();
  } else {
    
    const script = document.createElement('script');
    script.src ='//dapi.kakao.com/v2/maps/sdk.js?autoload=false&amp;amp;appkey=' + import.meta.env.VITE_APP_KAKAO_KEY;
    script.onload = () =&amp;gt; {
      kakao.maps.load(() =&amp;gt; {      
        kakao.maps.load(loadMap);
      });
    }
    
    document.head.appendChild(script);
  }
});
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. displayMarkers 를 분명 초기화 하는데도 불구하고 카카오맵 마커가 삭제가 되지 않는 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;=&amp;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;2. vue3.js 에서 전역변수 개념이 자바스크립트 환경이란 다른 건 지 ?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차 코드 수정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1695549740583&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;flex flex-col my-10&quot;&amp;gt;
    &amp;lt;h2 class=&quot;px-5 mb-3 text-lg font-semibold&quot;&amp;gt;주변을 둘러 보세요&amp;lt;/h2&amp;gt;
    &amp;lt;div id=&quot;map&quot; class=&quot;w-full h-[500px]&quot;&amp;gt;
      &amp;lt;!-- input --&amp;gt;
      &amp;lt;div class=&quot;absolute z-[99] p-3 w-full&quot;&amp;gt;
        &amp;lt;div class=&quot;flex items-center w-full p-3 bg-white rounded-md shadow-md&quot;&amp;gt;
          &amp;lt;i class=&quot;mr-2 text-xl las la-search text-zinc-400&quot;&amp;gt;&amp;lt;/i&amp;gt;
            &amp;lt;input  
                v-model=&quot;searchWord&quot; 
                @keyup.enter=&quot;onEnter&quot;
                type=&quot;text&quot; 
                placeholder=&quot;지금, 경주를 검색해보세요!&quot; 
            /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;style&amp;gt;
    .wrap {position: absolute;left: 0;bottom: 40px;width: 288px;height: 132px;margin-left: -144px;text-align: left;overflow: hidden;font-size: 12px;font-family: 'Malgun Gothic', dotum, '돋움', sans-serif;line-height: 1.5;}
    .wrap * {padding: 0;margin: 0;}
    .wrap .info {width: 286px;height: 120px;border-radius: 5px;border-bottom: 2px solid #ccc;border-right: 1px solid #ccc;overflow: hidden;background: #fff;}
    .wrap .info:nth-child(1) {border: 0;box-shadow: 0px 1px 2px #888;}
    .info .title {padding: 5px 0 0 10px;height: 30px;background: #eee;border-bottom: 1px solid #ddd;font-size: 18px;font-weight: bold;}
    .info .close {position: absolute;top: 10px;right: 10px;color: #888;width: 17px;height: 17px;background: url('https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/overlay_close.png');}
    .info .close:hover {cursor: pointer;}
    .info .body {position: relative;overflow: hidden;}
    .info .desc {position: relative;margin: 13px 0 0 90px;height: 75px;}
    .desc .ellipsis {overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}
    .desc .jibun {font-size: 11px;color: #888;margin-top: -2px;}
    .info .img {position: absolute;top: 6px;left: 5px;width: 73px;height: 71px;border: 1px solid #ddd;color: #888;overflow: hidden;}
    .info:after {content: '';position: absolute;margin-left: -12px;left: 50%;bottom: 0;width: 22px;height: 12px;background: url('https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/vertex_white.png')}
    .info .link {color: #5085BB;}
&amp;lt;/style&amp;gt;

&amp;lt;script setup&amp;gt;
import { onMounted, ref } from 'vue';
import { searchTrip } from '@/api';


const searchWord = ref('');

let map,displayMarkers = [];

const submit = async () =&amp;gt; {
  if (!searchWord.value) {
    alert('검색어를 입력하세요.');
    return;
  }

  try {
    const payload = {
      numOfRows: 10,
      pageNo: 1,
      MobileOS: 'ETC',
      MobileApp: 'AppTest',
      _type: 'json',
      listYN: 'Y',
      contentTypeId: '',
      arrange: 'A',
      areaCode: '',
      sigunguCode: '',
      cat1: '',
      cat2: '',
      cat3: '',
      keyword: searchWord.value,
    };

     await searchTrip(payload).then((result)=&amp;gt;{
    const {status, data: {response: { body }}} = result;
      console.log(displayMarkers);

        if (status === 200 &amp;amp;&amp;amp; body &amp;amp;&amp;amp; body.items.item.length &amp;gt; 0) {
            map.relayout();
            hideMarkers();
            body.items.item.forEach(item =&amp;gt; {
              let kakaoPos = new kakao.maps.LatLng(item.mapy, item.mapx);

              addMarker(kakaoPos,item,map);

            });

            let firstSearchMapPos = new kakao.maps.LatLng(body.items.item[0].mapy , body.items.item[0].mapx);
            map.setCenter(firstSearchMapPos);
            showMarkers(map);

        }else{
          alert(&quot;검색 결과가 없습니다.&quot;);
        }
    });
        
  } catch (error) {
    console.log(error);
  }
};

function addMarker(_position,_item,_map) {
    let marker = new kakao.maps.Marker({
      map: _map,
      position: _position,
      title: _item.title,
      clickable: true
    });

    let imageSrc = &quot;http://t1.daumcdn.net/localimg/localimages/07/mapapidoc/markerStar.png&quot;;
    let imageSize = new kakao.maps.Size(37, 45);
    let imageOption = { offset: new kakao.maps.Point(17, 40) };

    let markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption);
    let markerPosition = marker.getPosition();

    marker = new kakao.maps.Marker({
      position: markerPosition,
      // image: markerImage
    });

    marker.setMap(_map);
    let imgUrl = (_item.firstimage === null || _item.firstimage === &quot;&quot;  ? &quot;/svg/empty_face.svg&quot; : _item.firstimage);

    let contentHtml =  `&amp;lt;div class=&quot;wrap&quot;&amp;gt;
                          &amp;lt;div class=&quot;info&quot;&amp;gt;
                            &amp;lt;div class=&quot;title&quot;&amp;gt;
                              ${_item.title}
                              &amp;lt;div class=&quot;close&quot; onclick=&quot;closeOverlay()&quot; title=&quot;닫기&quot;&amp;gt;&amp;lt;/div&amp;gt;
                            &amp;lt;/div&amp;gt;
                            &amp;lt;div class=&quot;body&quot;&amp;gt;
                              &amp;lt;div class=&quot;img&quot;&amp;gt;
                                &amp;lt;img src=${imgUrl} width=&quot;73&quot; height=&quot;70&quot;&amp;gt;
                              &amp;lt;/div&amp;gt;
                              &amp;lt;div class=&quot;desc&quot;&amp;gt;
                                &amp;lt;div class=&quot;ellipsis&quot;&amp;gt;&amp;lt;/div&amp;gt;
                                &amp;lt;div class=&quot;jibun ellipsis&quot;&amp;gt;${_item.addr1 + &quot; &quot; + _item.addr2}&amp;lt;/div&amp;gt;
                                &amp;lt;div&amp;gt;&amp;lt;a href=${&quot;/trips/&quot; + _item.contentid + &quot;/&quot; +_item.contenttypeid} class=&quot;link&quot;&amp;gt;상세보기&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
                              &amp;lt;/div&amp;gt;
                            &amp;lt;/div&amp;gt;
                          &amp;lt;/div&amp;gt;
                        &amp;lt;/div&amp;gt;
                      `;
    
      let overlay = new kakao.maps.CustomOverlay({
          content: contentHtml,
          map: _map,
          position: marker.getPosition()       
      });


      kakao.maps.event.addListener(marker, 'click', function() {
          overlay.setMap(_map);
      });
      
    displayMarkers.push(marker);
    console.debug(&quot;push Markers&quot;,displayMarkers);
}

function showMarkers(_map) {
    setMarkers(_map);
}

function hideMarkers() {
    setMarkers(null);    
}

function setMarkers(_map) {
    for (var i = 0; i &amp;lt; displayMarkers.length; i++) {
        displayMarkers[i].setMap(_map);
    }
    console.debug(&quot;setMarkers&quot;,displayMarkers,_map);            
}

function closeOverlay() {
    console.debug(&quot;closeOverlay&quot;);
    overlay.setMap(null);     
}

const onEnter = () =&amp;gt; {
  submit(searchWord.value);
};

const getLocation = () =&amp;gt; {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition((position) =&amp;gt; {
      const myPosition = new kakao.maps.LatLng(position.coords.latitude, position.coords.longitude);
      map.setCenter(myPosition);

      const marker = new kakao.maps.Marker({
        position: myPosition,
        map: map,
      });
    });
  } else {
    console.log('getLocation error');
  }
};

const loadMap = () =&amp;gt; {
  const container = document.getElementById('map');
  const options = {
    center: new kakao.maps.LatLng(33.450701, 126.570667),
    level: 7,
  };
  map = new kakao.maps.Map(container, options);

  getLocation();
};

onMounted(() =&amp;gt; {
  if (window.kakao &amp;amp;&amp;amp; window.kakao.maps) {
    loadMap();
  } else {
    
    const script = document.createElement('script');
    script.src ='//dapi.kakao.com/v2/maps/sdk.js?autoload=false&amp;amp;appkey=' + import.meta.env.VITE_APP_KAKAO_KEY;
    script.onload = () =&amp;gt; {
      kakao.maps.load(() =&amp;gt; {      
        kakao.maps.load(loadMap);
      });
    }
    
    document.head.appendChild(script);
  }
});
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>변소</category>
      <category>kakaomap</category>
      <category>vue.js</category>
      <category>카카오맵</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/23</guid>
      <comments>https://djlife.tistory.com/23#entry23comment</comments>
      <pubDate>Sun, 24 Sep 2023 17:15:49 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot 환경에서 Appium을 통해 모바일 환경 테스트 하기 + 플러그인 (09.19 수정)</title>
      <link>https://djlife.tistory.com/22</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;appium-logo-horiz.png&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2pFvj/btsuk4kOaKa/HuBwO5ENjKCpimElUovYBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2pFvj/btsuk4kOaKa/HuBwO5ENjKCpimElUovYBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2pFvj/btsuk4kOaKa/HuBwO5ENjKCpimElUovYBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2pFvj%2Fbtsuk4kOaKa%2FHuBwO5ENjKCpimElUovYBk%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;1006&quot; height=&quot;216&quot; data-filename=&quot;appium-logo-horiz.png&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추후 모바일 환경을 테스트 하기 위한&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;appium 서버를 구축하고 java 와 통신하며 app 및 web 을 테스트 하기 위한 환경을 구축 하였다.&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;모바일 환경 앱 및 웹을 테스트 할 때 주로 쓰인다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언어는 &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;Java, Python, Ruby, JS 지원하니 모바일 디바이스 개발을 많이 하시는 분들이라 하면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;유용한 테스트 도구 인 것 같다.  &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;*&lt;span&gt;&lt;span&gt; appium &lt;/span&gt;(앱이움)&lt;/span&gt;&amp;nbsp;:&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt; Appium&amp;nbsp;은&amp;nbsp;웹&amp;nbsp;드라이버를&amp;nbsp;사용하여&amp;nbsp;Android&amp;nbsp;또는&amp;nbsp;iOS&amp;nbsp;에서&amp;nbsp;스크립트를&amp;nbsp;실행하고&amp;nbsp;기본&amp;nbsp;애플리케이션,&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;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; 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;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;appium 저장소에 이슈 남겼더니..&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;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;진행상황&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;appium Server 구축 통신 확인&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;java 코드로 모바일 환경에서 브라우저 이동 또는 앱 실행 확인&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이슈 &amp;amp; 고민 및 해결&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. appium java-client는 cdp를 지원하지 않고 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;=&amp;gt; &lt;a title=&quot;관련 이슈 링크&quot; href=&quot;https://github.com/appium/java-client/issues/2013&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;관련 이슈 링크&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;2. cdp와 통신하기 위한 방법을 찾아야 한다. 현재로서는 어려운 상황  &lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;통신 방법을 찾지 못한다면 결국 웹앱을 하나 만들어서 확인하는 방법 외에는 없는 것으로 생각된다..  &lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694883762063&quot; class=&quot;bash&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugins {
	id 'java'
	id 'org.springframework.boot' version '3.1.3'
	id 'io.spring.dependency-management' version '1.1.3'
}

group = 'com.acp'
version = '0.0.1-SNAPSHOT'

java {
	sourceCompatibility = '17'
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '4.12.1'
	implementation group: 'io.github.bonigarcia', name: 'webdrivermanager', version: '5.5.3'
	implementation 'org.seleniumhq.selenium:selenium-http-jdk-client:4.9.1'
	implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.15.2'
	implementation group: 'io.appium', name: 'java-client', version: '8.5.1'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.h2database:h2'
	runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.batch:spring-batch-test'
}

tasks.named('test') {
	useJUnitPlatform()
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://appium.io/docs/en/2.1/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://appium.io/docs/en/2.1/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1694884494105&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Appium Documentation - Appium Documentation&quot; data-og-description=&quot;Appium Documentation Welcome to the Appium documentation! Appium is an open-source project and ecosystem of related software, designed to facilitate UI automation of many app platforms, including mobile (iOS, Android, Tizen), browser (Chrome, Firefox, Safa&quot; data-og-host=&quot;appium.io&quot; data-og-source-url=&quot;https://appium.io/docs/en/2.1/&quot; data-og-url=&quot;https://appium.io/docs/en/2.1/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/EJwmo/hyTV0yjCzC/phsgtmn5Y4fO0CLIpps6U1/img.png?width=1006&amp;amp;height=216&amp;amp;face=0_0_1006_216&quot;&gt;&lt;a href=&quot;https://appium.io/docs/en/2.1/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://appium.io/docs/en/2.1/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/EJwmo/hyTV0yjCzC/phsgtmn5Y4fO0CLIpps6U1/img.png?width=1006&amp;amp;height=216&amp;amp;face=0_0_1006_216');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Appium Documentation - Appium Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Appium Documentation Welcome to the Appium documentation! Appium is an open-source project and ecosystem of related software, designed to facilitate UI automation of many app platforms, including mobile (iOS, Android, Tizen), browser (Chrome, Firefox, Safa&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;appium.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://github.com/appium/java-client&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/appium/java-client&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1694884560113&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - appium/java-client: Java language binding for writing Appium Tests, conforms to W3C WebDriver Protocol&quot; data-og-description=&quot;Java language binding for writing Appium Tests, conforms to W3C WebDriver Protocol - GitHub - appium/java-client: Java language binding for writing Appium Tests, conforms to W3C WebDriver Protocol&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/appium/java-client&quot; data-og-url=&quot;https://github.com/appium/java-client&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pmelg/hyTV2XcGxE/Uk0hYWnBF0aPW8hpImopq0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/appium/java-client&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/appium/java-client&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pmelg/hyTV2XcGxE/Uk0hYWnBF0aPW8hpImopq0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - appium/java-client: Java language binding for writing Appium Tests, conforms to W3C WebDriver Protocol&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Java language binding for writing Appium Tests, conforms to W3C WebDriver Protocol - GitHub - appium/java-client: Java language binding for writing Appium Tests, conforms to W3C WebDriver Protocol&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/appium/appium-desktop/releases&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/appium/appium-desktop/releases&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1694885327723&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Releases &amp;middot; appium/appium-desktop&quot; data-og-description=&quot;Appium Server in Desktop GUIs for Mac, Windows, and Linux - appium/appium-desktop&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/appium/appium-desktop/releases&quot; data-og-url=&quot;https://github.com/appium/appium-desktop/releases&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gs0s5/hyTVXO7MoU/SiNUVFaAzBUqGzfNchfP71/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/appium/appium-desktop/releases&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/appium/appium-desktop/releases&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gs0s5/hyTVXO7MoU/SiNUVFaAzBUqGzfNchfP71/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Releases &amp;middot; appium/appium-desktop&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Appium Server in Desktop GUIs for Mac, Windows, and Linux - appium/appium-desktop&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/mykola-mokhnach/appium-devtools-plugin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/mykola-mokhnach/appium-devtools-plugin&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1695093365095&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - mykola-mokhnach/appium-devtools-plugin: Appium plugin that adds proxy features to Android mobile webviews&quot; data-og-description=&quot;Appium plugin that adds proxy features to Android mobile webviews - GitHub - mykola-mokhnach/appium-devtools-plugin: Appium plugin that adds proxy features to Android mobile webviews&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/mykola-mokhnach/appium-devtools-plugin&quot; data-og-url=&quot;https://github.com/mykola-mokhnach/appium-devtools-plugin&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b6yGYa/hyTY7JPUdL/6c6BOOMXcaGx5OkZoDWoc1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/mykola-mokhnach/appium-devtools-plugin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/mykola-mokhnach/appium-devtools-plugin&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b6yGYa/hyTY7JPUdL/6c6BOOMXcaGx5OkZoDWoc1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - mykola-mokhnach/appium-devtools-plugin: Appium plugin that adds proxy features to Android mobile webviews&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Appium plugin that adds proxy features to Android mobile webviews - GitHub - mykola-mokhnach/appium-devtools-plugin: Appium plugin that adds proxy features to Android mobile webviews&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TO DO List&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. appium cdp 소켓 통신 확인하기&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 1이 안될 경우 insept로 가상 디바이스 접근하여 확인하기&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example Code&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;디바이스가 크롬 app을 실행한 후 해당 블로그로 이동하는 코드 sample code&lt;/p&gt;
&lt;pre id=&quot;code_1694883762068&quot; class=&quot;bash&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.acp.AbusingCheckProject.job;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;
import io.appium.java_client.remote.MobileCapabilityType;
import org.openqa.selenium.devtools.DevTools;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.net.URL;
import java.time.Duration;

@Component
public class NetworkMonitoringMobile {

    @Scheduled(fixedRate = 500000000)
    public void executeNetworkMonitoring() throws Exception {
        AppiumDriver driver = setupMobileWeb();
        driver.get(&quot;https://djlife.tistory.com/&quot;);


    }

    private AppiumDriver setupMobileWeb() {
        UiAutomator2Options capabilities = new UiAutomator2Options();

        capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, &quot;Android&quot;);
        capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, &quot;14&quot;);
        capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, &quot;emulator-5554&quot;); 
        capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, &quot;UiAutomator2&quot;);
        capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, &quot;Chrome&quot;);

        capabilities.setCapability(&quot;chromedriverExecutable&quot;, System.getProperty(&quot;webdriver.chrome.driver&quot;));

        // Open browser.
        AppiumDriver driver = null;

        try{
            driver = new AppiumDriver(new URL(&quot;http://127.0.0.1:4723/wd/hub&quot;),capabilities);
        }catch (Exception e){
            e.printStackTrace();
        }

        driver.manage()
                .timeouts()
                .implicitlyWait(Duration.ofSeconds(60));
        return driver;
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>appim</category>
      <category>appium driver</category>
      <category>appium server gui</category>
      <category>chrome</category>
      <category>Java 모바일 환경 테스트</category>
      <category>Spring 모바일 디바이스 접근</category>
      <category>모바일 테스트 도구</category>
      <category>셀레니움</category>
      <category>아피움</category>
      <category>안드로이드</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/22</guid>
      <comments>https://djlife.tistory.com/22#entry22comment</comments>
      <pubDate>Sun, 17 Sep 2023 02:22:54 +0900</pubDate>
    </item>
    <item>
      <title>Selenium 을 이용하여 특정 URL 요청과 응답 값 모니터링 하는 기능 만들기</title>
      <link>https://djlife.tistory.com/21</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Selenium_logo.svg.png&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;125&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqy764/btstkUxeqev/Bw4RaeoWS6FrkxAZrebNZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqy764/btstkUxeqev/Bw4RaeoWS6FrkxAZrebNZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqy764/btstkUxeqev/Bw4RaeoWS6FrkxAZrebNZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbqy764%2FbtstkUxeqev%2FBw4RaeoWS6FrkxAZrebNZk%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;512&quot; height=&quot;125&quot; data-filename=&quot;Selenium_logo.svg.png&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;125&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번에 내가 맡게 된 업무는 셀레니움과 jpa를 이용하여&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;특정 url 요청이 있는 지 확인하고&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그 요청으로 인한 응답 값을 모니터링 및 데이터를 적재하는 업무다  &lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사실 이번에 셀레니움을 이용하여 간단하게 개발을 하였지만&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아쉬움이 너무 많이 남았다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;셀레니움으로 chrome inspect device를 충분히 조작할 수 있을 것이라고 생각했지만..&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;내가 잘 모르는건지 내 생각과 달리 디바이스의 dom이나 script 를 조작하지 못했다..  &lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그렇지만, 모바일 환경에 테스트 자동 도구에는 어떤 것들이 있는지 알아보게 되었고&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다음 같은 상황이 생겼을 때는 더 빠르게 기술을 결정 할 수 있을 것 같다.  &lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;( ex&amp;nbsp; appium )&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;*&lt;span&gt; 셀레니움(셀레늄)&lt;/span&gt;&amp;nbsp;:&lt;span&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;플레이백&amp;nbsp;도구를&amp;nbsp;제공한다.&amp;nbsp;(셀례늄&amp;nbsp;IDE)&amp;nbsp;C&amp;nbsp;샤프,&amp;nbsp;그루비,&amp;nbsp;자바,&amp;nbsp;펄,&amp;nbsp;PHP,&amp;nbsp;파이썬,&amp;nbsp;루비,&amp;nbsp;스칼라&amp;nbsp;등&amp;nbsp;수많은&amp;nbsp;유명&amp;nbsp;프로그래밍&amp;nbsp;언어들에서&amp;nbsp;테스트를&amp;nbsp;작성하기&amp;nbsp;위한&amp;nbsp;테스트&amp;nbsp;도메인&amp;nbsp;특화&amp;nbsp;언어(Selenese)를&amp;nbsp;제공한다.&amp;nbsp;이&amp;nbsp;테스트들은&amp;nbsp;현대의&amp;nbsp;대부분의&amp;nbsp;웹&amp;nbsp;브라우저에서&amp;nbsp;수행이&amp;nbsp;가능하다.&amp;nbsp;셀레늄은&amp;nbsp;윈도우,&amp;nbsp;리눅스,&amp;nbsp;macOS&amp;nbsp;플랫폼에서&amp;nbsp;디플로이된다.&amp;nbsp;아파치&amp;nbsp;2.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;있다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;진행상황&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모니터링 하기 위한 어느정도 구색은 갖추었고&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;jpa를 이용하여 간단하게 데이터베이스에 저장한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이슈 &amp;amp; 고민 및 해결&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 환경에 설치 된 크롬 버전 문제&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;=&amp;gt; webdrivermanager 해결 (주소 : &lt;a href=&quot;https://github.com/bonigarcia/webdrivermanager&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/bonigarcia/webdrivermanager&lt;/a&gt;)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이걸 이용하면 WebDriverManager.chromedriver().setup(); 코드 한줄로 해결 할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;번거롭게 경로 지정 , 웹드라이버 설치도 필요 없다  &lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 셀레니움으로 브라우저 403 , 500 오류 날 시&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 크롬 옵션에 &lt;b&gt;--remote-allow-origins=*&amp;nbsp;&lt;/b&gt;있는데도 불구하고 계속 오류가 난다면&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-http-jdk-client&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-http-jdk-client&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;자바(jdk) 11+ 이상 일 시 사용을 권장하니 오류가 계속 발생 할 시 의존성 추가를 권장한다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 jdk1.8 보다 상위 버전에서 발생하는 오류인 것 같은데 이 라이브러리로 해결 할 수 있다고 한다&lt;br /&gt;&lt;a href=&quot;https://www.selenium.dev/blog/2022/using-java11-httpclient/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.selenium.dev/blog/2022/using-java11-httpclient/&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;나는 해당 문제를 최대한 피하고자 진행 당 시 모두 최신버전을 이용하였다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1694014292302&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugins {
	id 'java'
	id 'org.springframework.boot' version '3.1.3'
	id 'io.spring.dependency-management' version '1.1.3'
}

group = 'com.acp'
version = '0.0.1-SNAPSHOT'

java {
	sourceCompatibility = '17'
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '4.12.1'
	implementation group: 'io.github.bonigarcia', name: 'webdrivermanager', version: '5.5.3'
	implementation 'org.seleniumhq.selenium:selenium-http-jdk-client:4.9.1'
	implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.15.2'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.h2database:h2'
	runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.batch:spring-batch-test'
}

tasks.named('test') {
	useJUnitPlatform()
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%85%80%EB%A0%88%EB%8A%84_(%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4)&quot;&gt;https://ko.wikipedia.org/wiki/%EC%85%80%EB%A0%88%EB%8A%84_(%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4)&lt;/a&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셀레니움 위키백과&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1694011024234&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;셀레늄 (소프트웨어) - 위키백과, 우리 모두의 백과사전&quot; data-og-description=&quot;위키백과, 우리 모두의 백과사전. 셀레늄(Selenium)은 웹 애플리케이션 자동화 및 테스트를 위한 포터블 프레임워크이다. 셀레늄은 테스트 스크립트 언어를 학습할 필요 없이 기능 테스트를 만들&quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%85%80%EB%A0%88%EB%8A%84_(%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4)&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/%EC%85%80%EB%A0%88%EB%8A%84_(%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4)&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/biwrpE/hyTPF2vCoW/PXv0kBFvFSphkPuflyeJ70/img.png?width=484&amp;amp;height=476&amp;amp;face=0_0_484_476,https://scrap.kakaocdn.net/dn/wkufJ/hyTPzOLgit/16bCnBEMjxz49oMsQIaPoK/img.png?width=484&amp;amp;height=476&amp;amp;face=0_0_484_476,https://scrap.kakaocdn.net/dn/doTkcm/hyTSBD93N0/j4ueQU1fv5O8vy3OR4d21K/img.png?width=220&amp;amp;height=216&amp;amp;face=0_0_220_216&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%85%80%EB%A0%88%EB%8A%84_(%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%85%80%EB%A0%88%EB%8A%84_(%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4)&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/biwrpE/hyTPF2vCoW/PXv0kBFvFSphkPuflyeJ70/img.png?width=484&amp;amp;height=476&amp;amp;face=0_0_484_476,https://scrap.kakaocdn.net/dn/wkufJ/hyTPzOLgit/16bCnBEMjxz49oMsQIaPoK/img.png?width=484&amp;amp;height=476&amp;amp;face=0_0_484_476,https://scrap.kakaocdn.net/dn/doTkcm/hyTSBD93N0/j4ueQU1fv5O8vy3OR4d21K/img.png?width=220&amp;amp;height=216&amp;amp;face=0_0_220_216');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;셀레늄 (소프트웨어) - 위키백과, 우리 모두의 백과사전&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;위키백과, 우리 모두의 백과사전. 셀레늄(Selenium)은 웹 애플리케이션 자동화 및 테스트를 위한 포터블 프레임워크이다. 셀레늄은 테스트 스크립트 언어를 학습할 필요 없이 기능 테스트를 만들&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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.selenium.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.selenium.dev/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셀레니움 Dev 홈페이지&lt;/p&gt;
&lt;figure id=&quot;og_1694011064107&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Selenium&quot; data-og-description=&quot;Selenium automates browsers. That's it!&quot; data-og-host=&quot;www.selenium.dev&quot; data-og-source-url=&quot;https://www.selenium.dev/&quot; data-og-url=&quot;https://www.selenium.dev/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ybnmy/hyTPHeYrzi/wbtPaakalETI2nRyXl9Ju1/img.png?width=1960&amp;amp;height=412&amp;amp;face=0_0_1960_412,https://scrap.kakaocdn.net/dn/bCp8KW/hyTPvewoLF/yOaoY0frh2xw0GlXKHaUsk/img.png?width=1494&amp;amp;height=384&amp;amp;face=0_0_1494_384&quot;&gt;&lt;a href=&quot;https://www.selenium.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.selenium.dev/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ybnmy/hyTPHeYrzi/wbtPaakalETI2nRyXl9Ju1/img.png?width=1960&amp;amp;height=412&amp;amp;face=0_0_1960_412,https://scrap.kakaocdn.net/dn/bCp8KW/hyTPvewoLF/yOaoY0frh2xw0GlXKHaUsk/img.png?width=1494&amp;amp;height=384&amp;amp;face=0_0_1494_384');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Selenium&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Selenium automates browsers. That's it!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.selenium.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/SeleniumHQ/selenium&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/SeleniumHQ/selenium&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셀레니움 Github&lt;/p&gt;
&lt;figure id=&quot;og_1694012618471&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - SeleniumHQ/selenium: A browser automation framework and ecosystem.&quot; data-og-description=&quot;A browser automation framework and ecosystem. Contribute to SeleniumHQ/selenium development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/SeleniumHQ/selenium&quot; data-og-url=&quot;https://github.com/SeleniumHQ/selenium&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJTosH/hyTSxBKWdX/WA6eHLlTBavt8frPfATkGk/img.jpg?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640&quot;&gt;&lt;a href=&quot;https://github.com/SeleniumHQ/selenium&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/SeleniumHQ/selenium&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJTosH/hyTSxBKWdX/WA6eHLlTBavt8frPfATkGk/img.jpg?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - SeleniumHQ/selenium: A browser automation framework and ecosystem.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A browser automation framework and ecosystem. Contribute to SeleniumHQ/selenium development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://chromedriver.chromium.org/downloads&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://chromedriver.chromium.org/downloads&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크롬 웹 드라이버 다운로드&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1694013235396&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;ChromeDriver - WebDriver for Chrome - Downloads&quot; data-og-description=&quot;Current Releases If you are using Chrome version 115 or newer, please consult the Chrome for Testing availability dashboard. This page provides convenient JSON endpoints for specific ChromeDriver version downloading. For older versions of Chrome, please se&quot; data-og-host=&quot;chromedriver.chromium.org&quot; data-og-source-url=&quot;https://chromedriver.chromium.org/downloads&quot; data-og-url=&quot;https://chromedriver.chromium.org/downloads&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bci5i7/hyTSy8nYQX/mimEYZrsuQeWuwNBDcX2L0/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000&quot;&gt;&lt;a href=&quot;https://chromedriver.chromium.org/downloads&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://chromedriver.chromium.org/downloads&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bci5i7/hyTSy8nYQX/mimEYZrsuQeWuwNBDcX2L0/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;ChromeDriver - WebDriver for Chrome - Downloads&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Current Releases If you are using Chrome version 115 or newer, please consult the Chrome for Testing availability dashboard. This page provides convenient JSON endpoints for specific ChromeDriver version downloading. For older versions of Chrome, please se&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;chromedriver.chromium.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TO DO List&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;모바일 환경 테스트 &amp;amp; 배치 또는 스케줄러&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. appium 검토해보기&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 지금은 스프링 스케줄 이용하고 있지만&amp;nbsp; 스프링 배치로 마이그레이션 해보기 ( 시간이 남을 경우  )&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example Code&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위키백과 예제코드 사용언어 Java&lt;/p&gt;
&lt;pre id=&quot;code_1694010078900&quot; class=&quot;html xml&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import static org.openqa.selenium.support.ui.ExpectedConditions.presenceOfElementLocated;
import java.time.Duration;

public class HelloSelenium {

    public static void main(String[] args) {
        WebDriver driver = new FirefoxDriver();
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
        try {
            driver.get(&quot;https://google.com/ncr&quot;);
            driver.findElement(By.name(&quot;q&quot;)).sendKeys(&quot;cheese&quot; + Keys.ENTER);
            WebElement firstResult = wait.until(presenceOfElementLocated(By.cssSelector(&quot;h3&quot;)));
            System.out.println(firstResult.getAttribute(&quot;textContent&quot;));
        } finally {
            driver.quit();
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;특정 URL 요청이 있는지 확인하고&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그 요청이 있다면 응답데이터 확인 후 Database에 저장하는 코드&lt;/p&gt;
&lt;pre id=&quot;code_1694011871958&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.acp.AbusingCheckProject.job;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v116.network.Network;
import org.openqa.selenium.devtools.v116.network.Network.GetResponseBodyResponse;
import org.openqa.selenium.devtools.v116.network.model.Request;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.acp.AbusingCheckProject.entity.logTbl;
import com.acp.AbusingCheckProject.repository.LogTblRepository;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.github.bonigarcia.wdm.WebDriverManager;

@Component
public class NetworkMonitoring {

    @Value(&quot;${chrome.driver}&quot;)
    public String driverPath;

    @Autowired
    private LogTblRepository logTblRepository;

    @Scheduled(fixedRate = 3600000)
    public void executeNetworkMonitoring() {
        try {
        // ChromeDriver 경로 설정
        WebDriverManager.chromedriver().setup();

        // Chrome 옵션 설정
        ChromeOptions options = new ChromeOptions();
        //options.setCapability(&quot;goog:chromeOptions&quot;, Map.of(&quot;w3c&quot;, false));
        Map&amp;lt;String, Object&amp;gt; deviceMetrics = new HashMap&amp;lt;&amp;gt;();
        deviceMetrics.put(&quot;width&quot;, 1078);
        deviceMetrics.put(&quot;height&quot;, 924);
        deviceMetrics.put(&quot;pixelRatio&quot;, 3.0);
        Map&amp;lt;String, Object&amp;gt; mobileEmulation = new HashMap&amp;lt;&amp;gt;();
        mobileEmulation.put(&quot;deviceMetrics&quot;, deviceMetrics);
        mobileEmulation.put(&quot;userAgent&quot;, &quot;Mozilla/5.0 (Linux; Android 8.0.0;&quot; +  &quot;Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) &quot; + &quot;Chrome/67.0.3396.99 Mobile Safari/537.36&quot;);
        options.setExperimentalOption(&quot;mobileEmulation&quot;, mobileEmulation);
        WebDriver driver = new ChromeDriver(options);

        // 페이지 로딩 타임아웃 설정
        driver.manage().deleteAllCookies();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(30));

        // Chrome DevTools 설정
        DevTools devTools = ((ChromeDriver) driver).getDevTools();
        devTools.createSession();
        devTools.send(Network.clearBrowserCookies());
        devTools.send(Network.setCacheDisabled(true));
        
        // Network.enable 활성화
        devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
        
        // 네트워크 이벤트 리스너 등록
        devTools.addListener(Network.requestWillBeSent(), entry -&amp;gt; {
            Request request = entry.getRequest();
            String requestUrl = request.getUrl();
            if (requestUrl.contains(&quot;요청 URL&quot;)) {
                System.out.println(&quot;요청이 발생했습니다: &quot; + requestUrl);
            }
            
	            if (requestUrl.contains(&quot;모니터링 요청 URL&quot;)) {
	              try {
	                  String responseContent = getResponseContent(requestUrl);
	                  System.out.println(&quot;응답이 발생했습니다: &quot; + responseContent);
	                  ObjectMapper om = new ObjectMapper();
	                  Map&amp;lt;String,Object&amp;gt; jsonMap = om.readValue(returnStr(responseContent),Map.class);
	                  
	                  logTbl logtbl = logTbl.builder()
	                                   .result(jsonMap.containsKey(&quot;a&quot;) ? (String) jsonMap.get(&quot;a&quot;) : &quot;&quot;)
	                                   .uid(jsonMap.containsKey(&quot;b&quot;) ? (String) jsonMap.get(&quot;b&quot;) : &quot;&quot;)
	                                   .fp(jsonMap.containsKey(&quot;c&quot;) ? (String) jsonMap.get(&quot;c&quot;) : &quot;&quot;)
	                                   .tc(jsonMap.containsKey(&quot;d&quot;) ? (String) jsonMap.get(&quot;d&quot;) : &quot;&quot;)
	                                   .sc(jsonMap.containsKey(&quot;e&quot;) ? (String) jsonMap.get(&quot;e&quot;) : &quot;&quot;)
	                                   .score(jsonMap.containsKey(&quot;f&quot;) ? (String) jsonMap.get(&quot;f&quot;) : &quot;&quot;)
	                                   .tg1(jsonMap.containsKey(&quot;g&quot;) ? (String) jsonMap.get(&quot;g&quot;) : &quot;&quot;)
	                                   .tg2(jsonMap.containsKey(&quot;h&quot;) ? (String) jsonMap.get(&quot;h&quot;) : &quot;&quot;)
	                                   .siteUrl(&quot;모니터링URL&quot;)
	                                   .logDate(LocalDateTime.now())
	                                   .build();
	                  
	                  logTblRepository.save(logtbl);
	                  driver.quit();   // WebDriver 종료
	              } catch (IOException e) {
	                  e.printStackTrace();
	              }
	          }
        });
        
        // 사이트로 이동
        driver.get(&quot;모니터링할URL&quot;);
        
        
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }

    private static String getResponseContent(String url) throws IOException {
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setRequestMethod(&quot;GET&quot;);

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            return response.toString();
        }
    }


    public String returnStr(String str){
        String filteredJson = &quot;&quot;;
        try{
            // JSON 문자열의 시작 위치를 찾습니다.
            int start = str.indexOf(&quot;(&quot;);

            // JSON 문자열의 끝 위치를 찾습니다.
            int end = str.lastIndexOf(&quot;)&quot;);

            // JSON 문자열을 추출합니다.
                filteredJson = str.substring(start + 1, end);
        }catch (Exception e){
            e.printStackTrace();
        }
        return filteredJson;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Develop/Back-End</category>
      <category>Java</category>
      <category>JPA</category>
      <category>Selenium</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>모니터링</category>
      <category>셀레니움</category>
      <category>스프링부트 스케줄</category>
      <category>테스트도구</category>
      <category>특정 URL 요청 모너터링</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/21</guid>
      <comments>https://djlife.tistory.com/21#entry21comment</comments>
      <pubDate>Thu, 7 Sep 2023 00:32:19 +0900</pubDate>
    </item>
    <item>
      <title>타임리프(Thymeleaf) 본격적으로 사용하기 ( +@ 타임리프 벤치마크 성능 비교)</title>
      <link>https://djlife.tistory.com/20</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;259&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XiePi/btsswgCs4lL/FkYzGb2U6gDeSEaviBtWgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XiePi/btsswgCs4lL/FkYzGb2U6gDeSEaviBtWgk/img.png&quot; data-alt=&quot;타임리프 로고 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XiePi/btsswgCs4lL/FkYzGb2U6gDeSEaviBtWgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXiePi%2FbtsswgCs4lL%2FFkYzGb2U6gDeSEaviBtWgk%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;1280&quot; height=&quot;259&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;259&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;타임리프 로고 이미지&lt;/figcaption&gt;
&lt;/figure&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;a title=&quot;글&quot; href=&quot;https://djlife.tistory.com/15&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;글&lt;/span&gt;&lt;/a&gt;이 있으니 먼저 보기 바란다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(타임리프와 jsp를 고민하고 있는 AA나 PL이 있다면 아래 타임리프 벤치마크 성능 링크도 남겨놓았으니 참고하면 좋을 듯)&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;아마 JSP에 익숙한 사람은 금방 손에 익을 것 같다.&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;이번에 내가 맡게 된 업무는&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;해당하는 동영상을 자체적으로 만들거나 또는 수정할 수 있게&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;진행상황&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서버에서 받은 데이터 조회 및 가공(포맷) 처리&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기존 자바스크립트로 데이터 append 하여 렌더링 하는 부분 타임리프로 처리&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이슈 &amp;amp; 고민 및 해결&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 타임리프는 서버 사이드 렌더링(SSL)이지 CSR이 아니라는 점&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;한 html에 두개 이상 &lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;fragment 정의 했을 경우&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;서버에서 받는 html 아닌 클라이언트에서 받으면 th:block 이 두개 나와 당황했다..&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;html 을 서버에서 받아 처리하는 방법과 th:if 로 조건 처리 하는 방법으로 명확하게 replace 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1693410280439&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot; xmlns:th=&quot;http://www.thymeleaf.org&quot;&amp;gt;
    &amp;lt;th:block th:fragment=&quot;fragmentA&quot;&amp;gt;
        &amp;lt;div class=&quot;djlife&quot;&amp;gt;
          퇴근하고싶다.
        &amp;lt;/div&amp;gt;
    &amp;lt;/th:block&amp;gt;
    &amp;lt;th:block th:fragment=&quot;fragmentB&quot;&amp;gt;
        &amp;lt;div class=&quot;djlife&quot;&amp;gt;
          집가고싶다.
        &amp;lt;/div&amp;gt;
    &amp;lt;/th:block&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1693410139296&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- 불러오는 페이지 --&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot; xmlns:th=&quot;http://www.thymeleaf.org&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;th:block th:replace=&quot;/fragments/fragmentTest :: fragmentA&quot;&amp;gt;&amp;lt;/th:block&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
	&amp;lt;h1&amp;gt;개발자는 어디까지 공부해야할까?&amp;lt;/h1&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 프론트 프레임워크 (react,vue ...) 처럼 상태 관리가 되지 않는다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터 변동 시 수동으로 데이터 처리를 해주어야 한다..  &lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 자바스크립트에서 동적 렌더링 할 때 처리를 보다 쉽게 가능&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트로 키워드 강조하는 것보다 타임리프로 키워드 강조하는게 더 간단하다  &lt;/p&gt;
&lt;pre id=&quot;code_1693530283968&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div&amp;gt;
    &amp;lt;em th:utext=&quot;'상품코드 ' + (${#strings.isEmpty(keyword) ? rowData.prdtCode : #strings.replace(rowData.prdtCode, keyword, '&amp;lt;b class=highlighted-text&amp;gt;' + keyword + '&amp;lt;/b&amp;gt;')})&quot;&amp;gt;상품코드&amp;lt;/em&amp;gt;
    &amp;lt;p th:utext=&quot;(${#strings.isEmpty(keyword) ? rowData.prdtName : #strings.replace(rowData.prdtName, keyword, '&amp;lt;b class=highlighted-text&amp;gt;' + keyword + '&amp;lt;/b&amp;gt;')})&quot;&amp;gt;상품명&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;&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;backend 코드는 생략!&lt;/p&gt;
&lt;p 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;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TO DO List&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 화면 &lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;fragment&lt;span&gt; 공통으로 쪼갤 수 있는 컴포넌트는 최대한 분기&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 타임리프 디버깅 방법 스터디&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 레퍼런스&lt;/b&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://djlife.tistory.com/17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://djlife.tistory.com/17&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1693405553048&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;타임리프(Thymeleaf) 사용 방법  및 문법 정리&quot; data-og-description=&quot;들어가기 전   지금 있는 회사는 view 템플릿 엔진으로 thymeleaf 를 사용하고 있기에 간단하게 정리하여 글을 남긴다. &amp;quot;아니 나는 백엔드 개발자인데 ?&amp;quot; &amp;quot;이거 몰라도 되는 거 아니야?&amp;quot;  &amp;zwj;♂️ &quot; data-og-host=&quot;djlife.tistory.com&quot; data-og-source-url=&quot;https://djlife.tistory.com/17&quot; data-og-url=&quot;https://djlife.tistory.com/17&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cVUoVP/hyTL8J6tBz/AzFpum17q7rkAWsKw2ErXk/img.png?width=800&amp;amp;height=162&amp;amp;face=0_0_800_162,https://scrap.kakaocdn.net/dn/3Njgf/hyTMbGPFgD/sCsf99pegygqJXbnbULxB1/img.png?width=800&amp;amp;height=162&amp;amp;face=0_0_800_162,https://scrap.kakaocdn.net/dn/mZoci/hyTMgnPykA/f1dnzbR38l2StriKgAUJu1/img.png?width=4109&amp;amp;height=833&amp;amp;face=0_0_4109_833&quot;&gt;&lt;a href=&quot;https://djlife.tistory.com/17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://djlife.tistory.com/17&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cVUoVP/hyTL8J6tBz/AzFpum17q7rkAWsKw2ErXk/img.png?width=800&amp;amp;height=162&amp;amp;face=0_0_800_162,https://scrap.kakaocdn.net/dn/3Njgf/hyTMbGPFgD/sCsf99pegygqJXbnbULxB1/img.png?width=800&amp;amp;height=162&amp;amp;face=0_0_800_162,https://scrap.kakaocdn.net/dn/mZoci/hyTMgnPykA/f1dnzbR38l2StriKgAUJu1/img.png?width=4109&amp;amp;height=833&amp;amp;face=0_0_4109_833');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;타임리프(Thymeleaf) 사용 방법 및 문법 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;들어가기 전   지금 있는 회사는 view 템플릿 엔진으로 thymeleaf 를 사용하고 있기에 간단하게 정리하여 글을 남긴다. &quot;아니 나는 백엔드 개발자인데 ?&quot; &quot;이거 몰라도 되는 거 아니야?&quot;  &amp;zwj;♂️&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;djlife.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://dzone.com/articles/modern-type-safe-template-engines-part-2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dzone.com/articles/modern-type-safe-template-engines-part-2&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1693317257915&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Modern Type-Safe Template Engines (Part 2) - DZone&quot; data-og-description=&quot;We wrap up this quick two-part series on modern template engines that introduce type-safety to the world of HTML by doing feature and performance comparisons.&quot; data-og-host=&quot;dzone.com&quot; data-og-source-url=&quot;https://dzone.com/articles/modern-type-safe-template-engines-part-2&quot; data-og-url=&quot;https://dzone.com/articles/modern-type-safe-template-engines-part-2&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cuDowE/hyTL3hhg5T/PdQg1a3QxvTMqK14KxGGs1/img.jpg?width=5616&amp;amp;height=3510&amp;amp;face=0_0_5616_3510&quot;&gt;&lt;a href=&quot;https://dzone.com/articles/modern-type-safe-template-engines-part-2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dzone.com/articles/modern-type-safe-template-engines-part-2&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cuDowE/hyTL3hhg5T/PdQg1a3QxvTMqK14KxGGs1/img.jpg?width=5616&amp;amp;height=3510&amp;amp;face=0_0_5616_3510');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Modern Type-Safe Template Engines (Part 2) - DZone&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;We wrap up this quick two-part series on modern template engines that introduce type-safety to the world of HTML by doing feature and performance comparisons.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dzone.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://smarterco.de/java-benchmark-thymeleaf-2.1.4-vs-thymeleaf-3.0-snapshot/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://smarterco.de/java-benchmark-thymeleaf-2.1.4-vs-thymeleaf-3.0-snapshot/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1693317305087&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Java: Benchmark Thymeleaf 2.1.4 vs Thymeleaf 3.0 SNAPSHOT&quot; data-og-description=&quot;Page of Kamil Wozniak, a freelance software architect / developer working in and around Hamburg, Germany.&quot; data-og-host=&quot;smarterco.de&quot; data-og-source-url=&quot;https://smarterco.de/java-benchmark-thymeleaf-2.1.4-vs-thymeleaf-3.0-snapshot/&quot; data-og-url=&quot;https://smarterco.de/java-benchmark-thymeleaf-2.1.4-vs-thymeleaf-3.0-snapshot/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/waE60/hyTL4UOvyE/s2q8EFpEphIUHROAZhk1yK/img.jpg?width=1680&amp;amp;height=329&amp;amp;face=0_0_1680_329&quot;&gt;&lt;a href=&quot;https://smarterco.de/java-benchmark-thymeleaf-2.1.4-vs-thymeleaf-3.0-snapshot/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://smarterco.de/java-benchmark-thymeleaf-2.1.4-vs-thymeleaf-3.0-snapshot/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/waE60/hyTL4UOvyE/s2q8EFpEphIUHROAZhk1yK/img.jpg?width=1680&amp;amp;height=329&amp;amp;face=0_0_1680_329');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Java: Benchmark Thymeleaf 2.1.4 vs Thymeleaf 3.0 SNAPSHOT&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Page of Kamil Wozniak, a freelance software architect / developer working in and around Hamburg, Germany.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;smarterco.de&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/thymeleaf/thymeleaf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/thymeleaf/thymeleaf&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1693410857252&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - thymeleaf/thymeleaf: Thymeleaf is a modern server-side Java template engine for both web and standalone environments.&quot; data-og-description=&quot;Thymeleaf is a modern server-side Java template engine for both web and standalone environments. - GitHub - thymeleaf/thymeleaf: Thymeleaf is a modern server-side Java template engine for both web ...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/thymeleaf/thymeleaf&quot; data-og-url=&quot;https://github.com/thymeleaf/thymeleaf&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/SjVWf/hyTMaHW2A3/wf7m8Fcm8FJhnV2sN1LKj0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/thymeleaf/thymeleaf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/thymeleaf/thymeleaf&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/SjVWf/hyTMaHW2A3/wf7m8Fcm8FJhnV2sN1LKj0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - thymeleaf/thymeleaf: Thymeleaf is a modern server-side Java template engine for both web and standalone environments.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Thymeleaf is a modern server-side Java template engine for both web and standalone environments. - GitHub - thymeleaf/thymeleaf: Thymeleaf is a modern server-side Java template engine for both web ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>thymeleaf</category>
      <category>Thymeleaf Benchmark</category>
      <category>타임리프</category>
      <category>타임리프 사용방법</category>
      <category>타임리프 성능비교</category>
      <category>타임리프 실무</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/20</guid>
      <comments>https://djlife.tistory.com/20#entry20comment</comments>
      <pubDate>Thu, 31 Aug 2023 00:52:25 +0900</pubDate>
    </item>
    <item>
      <title>JAVA 에서 FFMPEG를 통한 영상 정보 읽기 및 영상 인코딩(압축) 처리 도전기</title>
      <link>https://djlife.tistory.com/19</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8NdXryEFjMXYhItCYvNx7vdTinXJfouFFrhngaj7rfIOCBB0LvassnR7eEGt5RXsxQEecZlqDQLZrsh0MIY1mA.png&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4sLoU/btsrhH1EkbC/MKFuhfzKpliaO1hjbRMF6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4sLoU/btsrhH1EkbC/MKFuhfzKpliaO1hjbRMF6k/img.png&quot; data-alt=&quot;FFMPEG 로고&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4sLoU/btsrhH1EkbC/MKFuhfzKpliaO1hjbRMF6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4sLoU%2FbtsrhH1EkbC%2FMKFuhfzKpliaO1hjbRMF6k%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;2500&quot; height=&quot;670&quot; data-filename=&quot;8NdXryEFjMXYhItCYvNx7vdTinXJfouFFrhngaj7rfIOCBB0LvassnR7eEGt5RXsxQEecZlqDQLZrsh0MIY1mA.png&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;FFMPEG 로고&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발을 잘 모르는 사람들은 &quot;아니 이미 파일 업로드 기능이 있는데? 그냥 기존에 업로드 하던 부분 조금만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;손보면 되는거 아니야?&quot; 이렇게 말을 할 수도 있지만&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;해당 기능을 새로 만드는 것보다 어렵다..  &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;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;제일 힘들었던건 ffmpeg가 국내에 정보가 많이 없는 것 같다.  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 따라하기 좋은 예제를 github 이슈에 모아놓았다..&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;github 링크는 아래 레퍼런스에 남김 :)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;FFmpeg&lt;/b&gt;&lt;br /&gt;FFmpeg는 오디오와 비디오를 다루기 위한 오픈 소스 멀티미디어 프레임워크 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 도구는 다양한 형식의 미디어 파일을 변환, 편집, 인코딩, 디코딩하는 데 사용되고 FFmpeg는 커맨드 라인 인터페이스를 제공하며, 다양한 옵션을 통해 다양한 작업을 수행할 수 있다 &lt;br /&gt;&lt;br /&gt;사용 예시 커맨드&lt;br /&gt;1. 비디오 변환:&lt;/p&gt;
&lt;pre id=&quot;code_1692195499053&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ffmpeg -i input.mp4 -c:v libx264 -c:a aac output.mp4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 커맨드는 input.mp4` 파일을 H.264 비디오 코덱과 AAC 오디오 코덱을 사용하여 `output.mp4`로 변환하는 커맨드&lt;br /&gt;&lt;br /&gt;2. 오디오 추출:&lt;/p&gt;
&lt;pre id=&quot;code_1692195578726&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ffmpeg -i input.mp4 -vn output.mp3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 커맨드는 input.mp4` 파일에서 오디오를 추출하여 `output.mp3` 파일로 저장하는 커맨드&lt;br /&gt;&lt;br /&gt;3. 비디오 자르기:&lt;/p&gt;
&lt;pre id=&quot;code_1692195615306&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ffmpeg -i input.mp4 -ss 00:00:10 -t 00:00:20 -c:v copy -c:a copy output.mp4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 커맨드는 input.mp4` 파일에서 10초부터 30초까지의 구간을 자르아 `output.mp4`로 저장하는 커맨드&lt;br /&gt;&lt;br /&gt;&lt;b&gt;FFprobe&lt;/b&gt;&lt;br /&gt;FFprobe는 FFmpeg 프로젝트의 일부로서, 미디어 파일의 정보를 분석하는 도구인데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 오디오와 비디오 파일의 코덱, 해상도, 비트레이트 등의 정보를 확인할 수 있다!  &lt;br /&gt;&lt;br /&gt;사용 예시 커맨드&lt;/p&gt;
&lt;pre id=&quot;code_1692195667554&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ffprobe input.mp4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 커맨드는 `input.mp4` 파일에 대한 정보를 출력하는 커맨드 옵션으로는 json이나 xml 형식 문자열로 추출 가능&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1692195724659&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ffprobe -show_streams -select_streams v:0 -print_format json input.mp4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 커맨드는 `input.mp4` 파일의 비디오 스트림에 대한 정보를 JSON 형식으로 출력합니다. &lt;br /&gt;&lt;br /&gt;이 외에도 FFmpeg와 FFprobe에는 수많은 옵션과 기능이 있으며, 위의 예시는 일부에 불과하니 커맨드를 실행하기 전에 해당 도구의 공식문서를 꼭 참고하도록 해 그리고 위키도!&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;진행상황&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dropzone.js를 커스터마이징 하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동영상 업로드 및 썸네일 추출 이후 서버에 파일 및 데이터 처리 까지 완료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용량 5MB 초과 시 압축 로직&lt;/p&gt;
&lt;p 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;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;업무 중 이슈/고민 또는 해결내용&lt;/b&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 id=&quot;fprsl&quot; style=&quot;background-color: #ffffff; color: #1a0dab; text-align: start;&quot; href=&quot;https://www.google.com/search?sca_esv=557430156&amp;amp;q=%EB%B6%80%EB%94%AA%ED%9E%88%EB%8B%A4&amp;amp;spell=1&amp;amp;sa=X&amp;amp;ved=2ahUKEwin_vLfjeGAAxXSBt4KHQF6A1kQkeECKAB6BAgIEAE&quot; data-ved=&quot;2ahUKEwin_vLfjeGAAxXSBt4KHQF6A1kQkeECKAB6BAgIEAE&quot;&gt;&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;1. 로컬(개발) 환경에서 이상 없던 코드가 운영 환경에 반영하니&amp;nbsp; ffmpeg ,ffprobe 권한이 없어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;-&amp;gt;&amp;nbsp; &amp;nbsp;리눅스 서버 war 구동 중인 계정에 권한 변경으로 해결&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;2. 미디어 메타 인포 읽어 map으로 변환하여 클라이언트에서 비교하는 로직&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 아 이거 하면서 어질어질 했다 일단 추후에 나랑 비슷한걸 개발하게 되는 사람들에게 말해주면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;미디어 인포를 읽을 때는 ffmpeg가 아니라 ffprobe를 사용하자&amp;nbsp; 아래 예제 코드에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;내가 적용한 코드를 첨부해놓았다   아래 코드에 ffprobe를 이용한 커맨드도 있음  &amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-1. 무해화 로직 거친 파일을 검증해야되었기 때문에 서버에 파일 보낼 때는 바이러스 검사 후 이상 없는 파일을 보내 temp 파일로 메타 인포만 읽고 삭제하였다.. (추후 용량 고려하여)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ffmpeg 공식 문서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.ffmpeg.org/ffmpeg.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.ffmpeg.org/ffmpeg.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1692184796949&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;ffmpeg Documentation&quot; data-og-description=&quot;Table of Contents ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ... ffmpeg is a universal media converter. It can read a wide variety of inputs - including live grabbing/recording devices - filter, and t&quot; data-og-host=&quot;www.ffmpeg.org&quot; data-og-source-url=&quot;https://www.ffmpeg.org/ffmpeg.html&quot; data-og-url=&quot;https://www.ffmpeg.org/ffmpeg.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.ffmpeg.org/ffmpeg.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.ffmpeg.org/ffmpeg.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;ffmpeg Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Table of Contents ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ... ffmpeg is a universal media converter. It can read a wide variety of inputs - including live grabbing/recording devices - filter, and t&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.ffmpeg.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/sbwvss-mvc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/DongJu-Na/sbwvss-mvc&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ffmpeg 이용하면서 여러 기능 추가해본 git&lt;/p&gt;
&lt;figure id=&quot;og_1692184829374&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - DongJu-Na/sbwvss-mvc: Spring Boot WebMvc Video Streaming Server&quot; data-og-description=&quot;Spring Boot WebMvc Video Streaming Server. Contribute to DongJu-Na/sbwvss-mvc development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/DongJu-Na/sbwvss-mvc&quot; data-og-url=&quot;https://github.com/DongJu-Na/sbwvss-mvc&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cCPg4p/hyTFpKVn98/2iaCKzEsk5VlmexGev9ys1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/sbwvss-mvc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/DongJu-Na/sbwvss-mvc&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cCPg4p/hyTFpKVn98/2iaCKzEsk5VlmexGev9ys1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - DongJu-Na/sbwvss-mvc: Spring Boot WebMvc Video Streaming Server&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot WebMvc Video Streaming Server. Contribute to DongJu-Na/sbwvss-mvc development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/sbwvss-mvc/issues/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/DongJu-Na/sbwvss-mvc/issues/1&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효과나 사용할만한 예제 모아놓은 이슈 리스트&lt;/p&gt;
&lt;figure id=&quot;og_1692184839502&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;ffmpeg effect sample &amp;middot; Issue #1 &amp;middot; DongJu-Na/sbwvss-mvc&quot; data-og-description=&quot;https://medium.com/numatic-ventures/top-17-ffmpeg-commands-of-video-processing-64b587325d9e ffmpeg17가지 예제 커맨드&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/DongJu-Na/sbwvss-mvc/issues/1&quot; data-og-url=&quot;https://github.com/DongJu-Na/sbwvss-mvc/issues/1&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c5YoVF/hyTFnl2mX8/La8DncwbmFivWSsfXBtgyK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/sbwvss-mvc/issues/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/DongJu-Na/sbwvss-mvc/issues/1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c5YoVF/hyTFnl2mX8/La8DncwbmFivWSsfXBtgyK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;ffmpeg effect sample &amp;middot; Issue #1 &amp;middot; DongJu-Na/sbwvss-mvc&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;https://medium.com/numatic-ventures/top-17-ffmpeg-commands-of-video-processing-64b587325d9e ffmpeg17가지 예제 커맨드&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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;Example Code&lt;/b&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;미디어 인포 읽어오는 기능 (BackEnd)&lt;/p&gt;
&lt;pre id=&quot;code_1692186974802&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	@PostMapping(value = &quot;/getVideoMetaInfo&quot; , produces = &quot;application/json&quot;)
	@CheckAuth(value = true)
	public @ResponseBody Map&amp;lt;String,Object&amp;gt;  getVideoInfo(@RequestParam(value = &quot;file&quot; , required = true) MultipartFile file
	){
		Map&amp;lt;String,Object&amp;gt; result = new HashMap&amp;lt;String,Object&amp;gt;();
		try {
			File tempFile = File.createTempFile(&quot;temp&quot;, &quot;.mp4&quot;);
			file.transferTo(tempFile);
			String tempPath = tempFile.getAbsolutePath().replaceAll(&quot;\\\\&quot;, &quot;/&quot;);

			ProcessBuilder processBuilder = new ProcessBuilder(ffprobe ,&quot;-v&quot;,&quot;error&quot;,&quot;-show_format&quot; ,&quot;-show_streams&quot; , &quot;-of&quot; ,&quot;json&quot; ,tempPath);
			processBuilder.redirectErrorStream(true);
			Process process = processBuilder.start();

			InputStream inputStream = process.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

			String line;
			StringBuilder jsonOutput = new StringBuilder();
			Map&amp;lt;String,Object&amp;gt; jsonMap = null;
			while ((line = bufferedReader.readLine()) != null) {
				jsonOutput.append(line);
			}

			int exitCode = process.waitFor();

			if(jsonOutput.length() &amp;gt; 0 &amp;amp;&amp;amp; exitCode == 0){
				ObjectMapper om = new ObjectMapper();
				jsonMap = om.readValue(jsonOutput.toString(), new TypeReference&amp;lt;Map&amp;lt;String,Object&amp;gt;&amp;gt;() {});
			}

			result.put(&quot;metaData&quot;,jsonMap);
			result.put(&quot;resultCode&quot;,exitCode);
			tempFile.delete();

		} catch (Exception e) { //IOException | InterruptedException
			e.printStackTrace();
			result.put(&quot;metaData&quot;,null);
			result.put(&quot;resultCode&quot;,1);
		}
		return result;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미디어 메타 인포 읽어오기 FrontEnd&lt;/p&gt;
&lt;pre id=&quot;code_1692187244710&quot; class=&quot;yaml&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function getVideoMetaInfo(_file){
    var _result = null;
    var saveData = new FormData();
        saveData.append(&quot;file&quot;, _file);

     $.ajax({
            async: false,
            crossDomain: true,
            url: '/item/getVideoMetaInfo',
            method: &quot;POST&quot;,
            type: &quot;POST&quot;,
            data: saveData,
            mimeType: &quot;multipart/form-data&quot;,
            xhrFields: {
                withCredentials: false
            },
            dataType: &quot;json&quot;,
            processData: false,
            contentType: false,
            success: function(data) {
                _result = data;
            },
            error: function (request, status, error) {
                console.error(status,error);
            },
            cache: false
    });

    return _result;
}&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;pre id=&quot;code_1692187311330&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ProcessBuilder processBuilder = new ProcessBuilder(
						ffmpeg,
						&quot;-y&quot;,
						&quot;-v&quot;,
						&quot;error&quot;,
						&quot;-i&quot;,
						filePath + uploadPath,
						&quot;-strict&quot;,
						&quot;experimental&quot;,
						&quot;-f&quot;,
						&quot;mp4&quot;,
						&quot;-vcodec&quot;,
						&quot;libx264&quot;,
						&quot;-s&quot;,
						&quot;720x480&quot;,
						&quot;-r&quot;,
						&quot;24/1&quot;,
						&quot;-acodec&quot;,
						&quot;aac&quot;,
						&quot;-ac&quot;,
						&quot;1&quot;,
						&quot;-ar&quot;,
						&quot;48000&quot;,
						&quot;-b:a&quot;,
						&quot;32768&quot;,
						&quot;-sn&quot;,
						filePath + &quot;/&quot; + formatFileName
				);

				Process process = processBuilder.start();
				int exitCode = process.waitFor();

				if (exitCode == 0) {
					if (!&quot;local&quot;.equals(profileActive)) {
						Runtime.getRuntime().exec(&quot;chmod -R 777 &quot; + filePath + &quot;/&quot; + formatFileName);
					}

					File compressedFile = new File(filePath + &quot;/&quot; + formatFileName);
					long compressedFileSizeInBytes = compressedFile.length();

					if(compressedFileSizeInBytes &amp;gt; fiveMegaBytes){
						uploadPath = &quot;formatErrer-01&quot;;
						return uploadPath;
					}

					uploadPath = uploadPath.replace(newFileName,formatFileName);
				}else{
					uploadPath = &quot;formatErrer-01&quot;;
				}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>ffmpeg</category>
      <category>ffmpeg fade 효과</category>
      <category>ffprobe</category>
      <category>Java</category>
      <category>JavaScript</category>
      <category>xFade</category>
      <category>동영상 압축</category>
      <category>동영상 편집</category>
      <category>자바 동영상 용량 줄이기</category>
      <category>자바에서 동영상 압축하기</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/19</guid>
      <comments>https://djlife.tistory.com/19#entry19comment</comments>
      <pubDate>Wed, 16 Aug 2023 21:02:46 +0900</pubDate>
    </item>
    <item>
      <title>크롤링(Crawling) vs 스크래핑(Scraping) - 도대체 차이점이 뭔데?</title>
      <link>https://djlife.tistory.com/18</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7412.jpg&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coUllU/btsq1baoKl5/9OUVCWkLg6G697opaN1DWk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coUllU/btsq1baoKl5/9OUVCWkLg6G697opaN1DWk/img.jpg&quot; data-alt=&quot;이미지 출처 :limeproxies&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coUllU/btsq1baoKl5/9OUVCWkLg6G697opaN1DWk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoUllU%2Fbtsq1baoKl5%2F9OUVCWkLg6G697opaN1DWk%2Fimg.jpg&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;1000&quot; height=&quot;500&quot; data-filename=&quot;7412.jpg&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지 출처 :limeproxies&lt;/figcaption&gt;
&lt;/figure&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;/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;아마도 업무적 유사성으로&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;/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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;크롤링(Crawling)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;/b&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;불리는&amp;nbsp;프로그램은&amp;nbsp;주로&amp;nbsp;검색&amp;nbsp;엔진이나&amp;nbsp;웹&amp;nbsp;사이트가&amp;nbsp;새로운&amp;nbsp;내용을&amp;nbsp;발견하고&amp;nbsp;인덱싱하는&amp;nbsp;데&amp;nbsp;사용됩니다.&amp;nbsp;크롤링은&amp;nbsp;대량의&amp;nbsp;데이터를&amp;nbsp;수집하는&amp;nbsp;데&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;span&gt;web crawler&lt;/span&gt;)는 조직적, 자동화된 방법으로&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9B%94%EB%93%9C_%EC%99%80%EC%9D%B4%EB%93%9C_%EC%9B%B9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt; 월드 와이드 웹&lt;/span&gt;&lt;/a&gt;을 탐색하는 컴퓨터 프로그램이다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;웹 크롤러가 하는 작업을 '웹 크롤링'(web crawling) 혹은 '스파이더링'(spidering)이라 부른다. 검색 엔진과 같은 여러 사이트에서는 데이터의 최신 상태 유지를 위해 웹 크롤링한다. 웹 크롤러는 대체로 방문한 사이트의 모든 페이지의 복사본을 생성하는 데 사용되며, 검색 엔진은 이렇게 생성된 페이지를 보다 빠른 검색을 위해 인덱싱한다. 또한 크롤러는 링크 체크나 HTML 코드 검증과 같은 웹 사이트의 자동 유지 관리 작업을 위해 사용되기도 하며, 자동 이메일 수집과 같은 웹 페이지의 특정 형태의 정보를 수집하는 데도 사용된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;웹 크롤러는 봇이나 소프트웨어 에이전트의 한 형태이다. 웹 크롤러는 대개 시드(seeds)라고 불리는 URL 리스트에서부터 시작하는데, 페이지의 모든 하이퍼링크를 인식하여 URL 리스트를 갱신한다. 갱신된 URL 리스트는 재귀적으로 다시 방문한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;220px-WebCrawlerArchitecture.svg.png&quot; data-origin-width=&quot;220&quot; data-origin-height=&quot;168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzJXJh/btsq0Ec1UZV/pDWXskUWX4j6dsUsUab2Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzJXJh/btsq0Ec1UZV/pDWXskUWX4j6dsUsUab2Kk/img.png&quot; data-alt=&quot;웹 크롤러 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzJXJh/btsq0Ec1UZV/pDWXskUWX4j6dsUsUab2Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzJXJh%2Fbtsq0Ec1UZV%2FpDWXskUWX4j6dsUsUab2Kk%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;276&quot; height=&quot;211&quot; data-filename=&quot;220px-WebCrawlerArchitecture.svg.png&quot; data-origin-width=&quot;220&quot; data-origin-height=&quot;168&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;웹 크롤러 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&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;style3&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스크래핑(Scraping)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; 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;내에서&amp;nbsp;원하는&amp;nbsp;데이터를&amp;nbsp;정확하게&amp;nbsp;추출하는&amp;nbsp;작업을&amp;nbsp;의미합니다.&amp;nbsp;스크래핑은&amp;nbsp;웹&amp;nbsp;페이지의&amp;nbsp;HTML&amp;nbsp;코드나&amp;nbsp;XML과&amp;nbsp;같은&amp;nbsp;구조화된&amp;nbsp;데이터를&amp;nbsp;파싱하고&amp;nbsp;분석하여&amp;nbsp;필요한&amp;nbsp;정보를&amp;nbsp;추출합니다.&amp;nbsp;이러한&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;대충 어떤건지 알았으니&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;조금 더 기억에 오래 남도록&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;표로 정리해보자면 ... &lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 156px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;크롤링&amp;nbsp;(Crawling)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;스크래핑&amp;nbsp;(Scraping)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;정의&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;웹을&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt; 자동으로 탐색하여 링크를 따라가며 데이터를 수집하는 과정&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;수집한 웹 페이지 내에서 필요한 정보를 추출하는 과정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;목적&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;새로운 정보를 발견하고 인덱싱하기 위함&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;원하는 정보를 정제하고 활용하기 위함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;주체&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;크롤러(Crawler) 또는 스파이더(Spider)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;스크래퍼(Scraper)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;데이터 범위&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;여러 웹 페이지 및 사이트&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;특정 웹 페이지 또는 데이터 집합&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;작업 흐름&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;다양한 웹 페이지를 자동 탐색하여 데이터 수집&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;크롤링으로 수집한 웹 페이지에서 정보 추출&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;활용 예시&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;검색 엔진 인덱싱, 데이터 수집 및 분석 등&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;온라인 상품 가격 비교, 기사 분석 등&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;기술적 요소&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;웹 페이지의 링크 추적, 자동화 작업 등&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;HTML 파싱, CSS 선택자 활용, 정규 표현식 등&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;주의 사항&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;서버&amp;nbsp;부하,&amp;nbsp;로봇&amp;nbsp;배제&amp;nbsp;표준(Robots.txt)&amp;nbsp;준수&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;웹&amp;nbsp;사이트의&amp;nbsp;이용&amp;nbsp;약관을&amp;nbsp;준수하여&amp;nbsp;법적&amp;nbsp;문제&amp;nbsp;회피&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.hectodata.co.kr/crawling_vs_scraping/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.hectodata.co.kr/crawling_vs_scraping/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691858566738&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;비개발자가 쉽게 설명하는 웹 크롤링(Crawling)과 웹 스크래핑(Scraping)의 차이점&quot; data-og-description=&quot;여러 플랫폼들은 &amp;lsquo;웹 크롤링(Web Crawling)&amp;rsquo;과 &amp;lsquo;웹 스크래핑(Scrapint)&amp;rsquo; 기술을 활용하여 인터넷의 수많은 데이터 속에서 고객이 원하는 정보만을 골라 보여줍니다. 비슷한듯 다른 크롤링과 스크&quot; data-og-host=&quot;blog.hectodata.co.kr&quot; data-og-source-url=&quot;https://blog.hectodata.co.kr/crawling_vs_scraping/&quot; data-og-url=&quot;https://blog.codef.io/crawling_vs_scraping/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cjsaSi/hyTCJpDVYS/4DH0Dsu11jseddrHZN7G10/img.jpg?width=1604&amp;amp;height=900&amp;amp;face=0_0_1604_900,https://scrap.kakaocdn.net/dn/ckqmLD/hyTCDwb9ck/lTH2trKSBMBNIP8DKXkA4K/img.jpg?width=1604&amp;amp;height=900&amp;amp;face=0_0_1604_900,https://scrap.kakaocdn.net/dn/bDmVpT/hyTCG7vFhg/nUMnrFgXKQudMxXemJkx1K/img.png?width=2220&amp;amp;height=528&amp;amp;face=0_0_2220_528&quot;&gt;&lt;a href=&quot;https://blog.hectodata.co.kr/crawling_vs_scraping/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hectodata.co.kr/crawling_vs_scraping/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cjsaSi/hyTCJpDVYS/4DH0Dsu11jseddrHZN7G10/img.jpg?width=1604&amp;amp;height=900&amp;amp;face=0_0_1604_900,https://scrap.kakaocdn.net/dn/ckqmLD/hyTCDwb9ck/lTH2trKSBMBNIP8DKXkA4K/img.jpg?width=1604&amp;amp;height=900&amp;amp;face=0_0_1604_900,https://scrap.kakaocdn.net/dn/bDmVpT/hyTCG7vFhg/nUMnrFgXKQudMxXemJkx1K/img.png?width=2220&amp;amp;height=528&amp;amp;face=0_0_2220_528');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;비개발자가 쉽게 설명하는 웹 크롤링(Crawling)과 웹 스크래핑(Scraping)의 차이점&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;여러 플랫폼들은 &amp;lsquo;웹 크롤링(Web Crawling)&amp;rsquo;과 &amp;lsquo;웹 스크래핑(Scrapint)&amp;rsquo; 기술을 활용하여 인터넷의 수많은 데이터 속에서 고객이 원하는 정보만을 골라 보여줍니다. 비슷한듯 다른 크롤링과 스크&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hectodata.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9B%B9_%ED%81%AC%EB%A1%A4%EB%9F%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ko.wikipedia.org/wiki/%EC%9B%B9_%ED%81%AC%EB%A1%A4%EB%9F%AC&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691858587313&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;웹 크롤러 - 위키백과, 우리 모두의 백과사전&quot; data-og-description=&quot;위키백과, 우리 모두의 백과사전. 검색 엔진에 대해서는 웹크롤러 문서를 참고하십시오. 웹 크롤러의 구조. 웹 크롤러(web crawler)는 조직적, 자동화된 방법으로 월드 와이드 웹을 탐색하는 컴퓨터&quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%9B%B9_%ED%81%AC%EB%A1%A4%EB%9F%AC&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/%EC%9B%B9_%ED%81%AC%EB%A1%A4%EB%9F%AC&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ADqK8/hyTCGNc77S/YuxlABhlPuoii83KGNojR1/img.png?width=1200&amp;amp;height=917&amp;amp;face=0_0_1200_917,https://scrap.kakaocdn.net/dn/FjWhB/hyTCCKN7Fa/IpItkM0cG0EmTwRkmBi3G0/img.png?width=800&amp;amp;height=611&amp;amp;face=0_0_800_611,https://scrap.kakaocdn.net/dn/nrxWg/hyTCJDbuZ5/1pAOJ2b05Uc5AMqZju9xxK/img.png?width=640&amp;amp;height=489&amp;amp;face=0_0_640_489&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9B%B9_%ED%81%AC%EB%A1%A4%EB%9F%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%9B%B9_%ED%81%AC%EB%A1%A4%EB%9F%AC&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ADqK8/hyTCGNc77S/YuxlABhlPuoii83KGNojR1/img.png?width=1200&amp;amp;height=917&amp;amp;face=0_0_1200_917,https://scrap.kakaocdn.net/dn/FjWhB/hyTCCKN7Fa/IpItkM0cG0EmTwRkmBi3G0/img.png?width=800&amp;amp;height=611&amp;amp;face=0_0_800_611,https://scrap.kakaocdn.net/dn/nrxWg/hyTCJDbuZ5/1pAOJ2b05Uc5AMqZju9xxK/img.png?width=640&amp;amp;height=489&amp;amp;face=0_0_640_489');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;웹 크롤러 - 위키백과, 우리 모두의 백과사전&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;위키백과, 우리 모두의 백과사전. 검색 엔진에 대해서는 웹크롤러 문서를 참고하십시오. 웹 크롤러의 구조. 웹 크롤러(web crawler)는 조직적, 자동화된 방법으로 월드 와이드 웹을 탐색하는 컴퓨터&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://realpython.com/beautiful-soup-web-scraper-python/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://realpython.com/beautiful-soup-web-scraper-python/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691859351256&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Beautiful Soup: Build a Web Scraper With Python &amp;ndash; Real Python&quot; data-og-description=&quot;In this tutorial, you'll walk through the main steps of the web scraping process. You'll learn how to write a script that uses Python's requests library to scrape data from a website. You'll also use Beautiful Soup to extract the specific pieces of informa&quot; data-og-host=&quot;realpython.com&quot; data-og-source-url=&quot;https://realpython.com/beautiful-soup-web-scraper-python/&quot; data-og-url=&quot;https://realpython.com/beautiful-soup-web-scraper-python/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pBCW1/hyTCJpD2ve/nkoswuwMybxdheOLkMNF21/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080,https://scrap.kakaocdn.net/dn/xQk4W/hyTCJpD2li/CzrmeGgMm7IUaWubHSvmSK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080,https://scrap.kakaocdn.net/dn/dbriq4/hyTCBkPpV9/4zikBZskjVVfWKNkQ6J6lK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://realpython.com/beautiful-soup-web-scraper-python/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://realpython.com/beautiful-soup-web-scraper-python/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pBCW1/hyTCJpD2ve/nkoswuwMybxdheOLkMNF21/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080,https://scrap.kakaocdn.net/dn/xQk4W/hyTCJpD2li/CzrmeGgMm7IUaWubHSvmSK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080,https://scrap.kakaocdn.net/dn/dbriq4/hyTCBkPpV9/4zikBZskjVVfWKNkQ6J6lK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Beautiful Soup: Build a Web Scraper With Python &amp;ndash; Real Python&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;In this tutorial, you'll walk through the main steps of the web scraping process. You'll learn how to write a script that uses Python's requests library to scrape data from a website. You'll also use Beautiful Soup to extract the specific pieces of informa&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;realpython.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://wiki.hash.kr/index.php/%EC%8A%A4%ED%81%AC%EB%9E%98%ED%95%91&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://wiki.hash.kr/index.php/%EC%8A%A4%ED%81%AC%EB%9E%98%ED%95%91&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691859405544&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;스크래핑 - 해시넷&quot; data-og-description=&quot;스크래핑(Scraping)은 웹사이트(Web-Site)의 특정 페이지에서 정보를 자동으로 추출하는 기술이다. 이는 스크레이핑라고도 한다. 또 다른 스크래핑의 개념은 건축용어로 바닥이나 벽의 콘크리트면에&quot; data-og-host=&quot;wiki.hash.kr&quot; data-og-source-url=&quot;http://wiki.hash.kr/index.php/%EC%8A%A4%ED%81%AC%EB%9E%98%ED%95%91&quot; data-og-url=&quot;http://wiki.hash.kr/index.php/%EC%8A%A4%ED%81%AC%EB%9E%98%ED%95%91&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/z2QRv/hyTCE9H3rf/874yIxtszyeJTNY8aPK25K/img.jpg?width=1024&amp;amp;height=240&amp;amp;face=0_0_1024_240,https://scrap.kakaocdn.net/dn/ey8fR/hyTCNlhKJ9/t8gGyMix1VLfkEoKot6cXK/img.png?width=800&amp;amp;height=282&amp;amp;face=0_0_800_282,https://scrap.kakaocdn.net/dn/bNoJR3/hyTCA7jHoh/OK5KgiPkhy9kgdKDkNuLxK/img.jpg?width=213&amp;amp;height=750&amp;amp;face=0_0_213_750&quot;&gt;&lt;a href=&quot;http://wiki.hash.kr/index.php/%EC%8A%A4%ED%81%AC%EB%9E%98%ED%95%91&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://wiki.hash.kr/index.php/%EC%8A%A4%ED%81%AC%EB%9E%98%ED%95%91&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/z2QRv/hyTCE9H3rf/874yIxtszyeJTNY8aPK25K/img.jpg?width=1024&amp;amp;height=240&amp;amp;face=0_0_1024_240,https://scrap.kakaocdn.net/dn/ey8fR/hyTCNlhKJ9/t8gGyMix1VLfkEoKot6cXK/img.png?width=800&amp;amp;height=282&amp;amp;face=0_0_800_282,https://scrap.kakaocdn.net/dn/bNoJR3/hyTCA7jHoh/OK5KgiPkhy9kgdKDkNuLxK/img.jpg?width=213&amp;amp;height=750&amp;amp;face=0_0_213_750');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;스크래핑 - 해시넷&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;스크래핑(Scraping)은 웹사이트(Web-Site)의 특정 페이지에서 정보를 자동으로 추출하는 기술이다. 이는 스크레이핑라고도 한다. 또 다른 스크래핑의 개념은 건축용어로 바닥이나 벽의 콘크리트면에&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;wiki.hash.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://networkinterview.com/data-crawling-vs-data-scraping/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://networkinterview.com/data-crawling-vs-data-scraping/&lt;/a&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글을 읽어주셔서 감사합니다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; 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;</description>
      <category>변소</category>
      <category>Crawling</category>
      <category>Scraping</category>
      <category>스크래핑</category>
      <category>웹 스크래퍼</category>
      <category>웹 크롤러</category>
      <category>크롤링</category>
      <category>크롤링 vs 스크래핑</category>
      <category>크롤링과 스크래핑 차이점</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/18</guid>
      <comments>https://djlife.tistory.com/18#entry18comment</comments>
      <pubDate>Sun, 13 Aug 2023 02:14:40 +0900</pubDate>
    </item>
    <item>
      <title>타임리프(Thymeleaf) 사용 방법  및 문법 정리</title>
      <link>https://djlife.tistory.com/17</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;thymeleaf_logo_white.png&quot; data-origin-width=&quot;4109&quot; data-origin-height=&quot;833&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lveRL/btsqttJwItL/lv7NXbF8EZIREvi4tBDmQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lveRL/btsqttJwItL/lv7NXbF8EZIREvi4tBDmQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lveRL/btsqttJwItL/lv7NXbF8EZIREvi4tBDmQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlveRL%2FbtsqttJwItL%2Flv7NXbF8EZIREvi4tBDmQK%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;4109&quot; height=&quot;833&quot; data-filename=&quot;thymeleaf_logo_white.png&quot; data-origin-width=&quot;4109&quot; data-origin-height=&quot;833&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lksYc/btsp9qMn7Cf/FxzngWwCocKaeKIU7PAJN0/img.jpg&quot; data-lightbox=&quot;lightbox&quot; data-alt=&quot;&amp;amp;lt;image by toptal&amp;amp;gt;&quot;&gt;&lt;/span&gt;&lt;b&gt;들어가기 전&lt;/b&gt;  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 있는 회사는 view 템플릿 엔진으로 thymeleaf 를 사용하고 있기에 간단하게 정리하여 글을 남긴다.&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;아니 나는 백엔드 개발자인데 ?&quot; &quot;이거 몰라도 되는 거 아니야?&quot;  &amp;zwj;♂️&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;질 수도 있지만 열에 일곱은아닐 것이다  &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;이건 내 개인적인 생각이지만 리액트(react.js)나 뷰(vue.js)도 프론트 개발자 또는 퍼블리셔와 원활한 커뮤니케이션을 위해&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사이드 프로젝트로 해보는 것을 권장한다. (전에 스타트업에 잠깐 있었을 때 많은 도움이 되었다 특히 퍼블리셔와 소통하는 부분에서   나는 백엔드 개발자지만 당시 스타트업에 프론트 개발자가 채용 되지 않아 내가 리액트 즉 프론트를 담당하며&amp;nbsp; 백엔드 보조까지 하며 개발2팀 팀장을 하였다  .. 아마 일부 스타트업에서 이와 같은 일들이 빈번하게 일어날 텐데 무슨 말로도 위로가 안되겠지만 힘내라고 말해주고 싶다. 열심히 하다보면 알아주는 사람이 있기 마련이다. 이와 같이 말해줄 수 있는 이유는 당시 스타트업 대표가 입사 2개월만에 새 계약서를 제안 했었다. &lt;s&gt;근데 난 퇴사를 하였다&lt;/s&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 애플리케이션의 백엔드에서 서버 측의 데이터를 가져와서 동적으로 HTML을 생성하는 데 사용되며 백엔드 프레임워크(예: 스프링 프레임워크)와 같이 사용되어 웹 페이지의 내용을 동적으로 생성하거나 뷰 템플릿을 구성하는 데 주로 활용 되므로 여기 카테고리에 두었다.&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;내가 필요할 것 같은 것만 공부하여 축약 후 정리한 글이라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;타임리프란?&lt;/b&gt;&amp;nbsp; &lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Thymeleaf는&amp;nbsp;HTML,&amp;nbsp;XML,&amp;nbsp;JavaScript,&amp;nbsp;CSS&amp;nbsp;및&amp;nbsp;일반&amp;nbsp;텍스트를&amp;nbsp;처리할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;웹&amp;nbsp;및&amp;nbsp;독립&amp;nbsp;실행형&amp;nbsp;환경&amp;nbsp;모두를&amp;nbsp;위한&amp;nbsp;최신&amp;nbsp;서버&amp;nbsp;측&amp;nbsp;Java&amp;nbsp;템플릿&amp;nbsp;엔진입니다. &lt;br /&gt;&lt;br /&gt;Thymeleaf의&amp;nbsp;주요&amp;nbsp;목표는&amp;nbsp;우아하고&amp;nbsp;유지&amp;nbsp;관리가&amp;nbsp;쉬운&amp;nbsp;템플릿&amp;nbsp;생성&amp;nbsp;방법을&amp;nbsp;제공하는&amp;nbsp;것입니다.&amp;nbsp;이를&amp;nbsp;달성하기&amp;nbsp;위해&amp;nbsp;템플릿이&amp;nbsp;디자인&amp;nbsp;프로토타입으로&amp;nbsp;사용되는&amp;nbsp;데&amp;nbsp;영향을&amp;nbsp;미치지&amp;nbsp;않는&amp;nbsp;방식으로&amp;nbsp;템플릿&amp;nbsp;파일에&amp;nbsp;논리를&amp;nbsp;주입하는&amp;nbsp;Natural&amp;nbsp;Templates&amp;nbsp;의&amp;nbsp;개념을&amp;nbsp;기반으로&amp;nbsp;합니다&amp;nbsp;.&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;Thymeleaf는&amp;nbsp;또한&amp;nbsp;처음부터&amp;nbsp;웹&amp;nbsp;표준,&amp;nbsp;특히&amp;nbsp;HTML5를&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 style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;출처 : 타임리프 공식 문서(레퍼런스에 공식문서 URL&amp;nbsp; 참고 )&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문법 정리&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 117px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 99.9999%; height: 20px;&quot; colspan=&quot;3&quot;&gt;&lt;b&gt;간단한 표현&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;변수 표현식&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;${...}&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;변수&amp;nbsp;값&amp;nbsp;또는&amp;nbsp;객체&amp;nbsp;속성의&amp;nbsp;값을&amp;nbsp;출력&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;선택 변수 표현식&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;*{...}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;폼 데이터 바인딩을 위해 사용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;링크 URL 표현식&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;@{...}&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;링크 URL 생성&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 40px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;조각 표현식&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 40px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;~{...}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 40px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;조각(템플릿 조각)의 내용을 포함하는 곳에 사용&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 100px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 99.9999%; height: 20px;&quot; colspan=&quot;3&quot;&gt;리터럴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;텍스트&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;'one text'&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;문자열 리터럴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;숫자&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;0,34,3.0,12.3&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;정수 또는 부동 소수점 숫자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;불린&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;true,false&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;논리 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;널&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;null&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;널 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;리터럴 토큰&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;one,sometext,main...&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;미리 정의된 값&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 51px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 99.9999%; height: 17px;&quot; colspan=&quot;3&quot;&gt;문자 연산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;문자 합치기&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;+&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;문자열 연결&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;리터럴 대체&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;|&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;|&lt;/span&gt;The name is ${name}&lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;|&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 51px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 99.9999%; height: 17px;&quot; colspan=&quot;3&quot;&gt;산술 연산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #efefef; color: #374151; text-align: left;&quot;&gt;Binary operators&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;+, -, *, /, %&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;더하기, 빼기, 곱하기, 나누기, 나머지 연산&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Minus&amp;nbsp;sign&amp;nbsp;(unary&amp;nbsp;operatior)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;단항 마이너스 연산&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 57px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 99.9999%; height: 20px;&quot; colspan=&quot;3&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;불린&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt; 연산&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;Binary operators&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;and, or&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;논리 AND, OR 연산&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;Boolean negation&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;!, not&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;논리 NOT 연산&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 54px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 99.9999%; height: 20px;&quot; colspan=&quot;3&quot;&gt;비교와 동등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;비교&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&amp;gt;, &amp;lt;, &amp;gt;=, &amp;lt;=&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;크기 비교 연산&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;동등 연산&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;==, !=&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;동등 비교 연산&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 99.9999%;&quot; colspan=&quot;3&quot;&gt;조건 연산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;I&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;f-then&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;(if) ? (then)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;조건이 참이면 결과값 출력, 그렇지 않으면 무시&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;If-then-else&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;(if) ? (then) : (else)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;조건에 따라 두 가지 결과 중 하나 출력&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;Default&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;(value) ?: (defaultvalue)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;값이 있으면 출력, 없으면 기본값 출력&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 37px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 99.9999%; height: 20px;&quot; colspan=&quot;3&quot;&gt;특별한 토큰&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;No-Operation&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;_&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;아무것도 하지 않음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;p data-ke-size=&quot;size16&quot;&gt;서버에서 Model 에 담은 값을 타임리프에서는 아래와 같이 표현 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.&lt;span style=&quot;color: #006dd7;&quot;&gt;[[...]]&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691425098519&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;p&amp;gt;Hello, [[${name}]]!&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;span style=&quot;color: #006dd7;&quot;&gt;th:text&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691425121688&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;p&amp;gt;Hello, &amp;lt;span th:text=&quot;${name}&quot;&amp;gt;하얀단화&amp;lt;/span&amp;gt;!&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;만일 * HTML 엔티티를 제외 하려면&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;[(...)] 또는 th:utext 를 사용하면 된다. 사용 방법은 아래와 같다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;* &lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;HTML 엔티티 : &lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;HTML에서 특정 캐릭터들이 예약되어있기 때문에 표기의 혼란을 막기 위해서 사용하는 것 &lt;/span&gt;ex)&amp;nbsp; &amp;lt; 또는 &amp;gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[(...)]&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691425506457&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;p&amp;gt;Hello, [(${name})]!&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&lt;span style=&quot;color: #006dd7;&quot;&gt;th:utext&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691425561238&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;p&amp;gt;Hello, &amp;lt;span th:utext=&quot;${name}&quot;&amp;gt;하얀단화&amp;lt;/span&amp;gt;!&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;span style=&quot;color: #006dd7;&quot;&gt;th:block&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691426091430&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html lagn=&quot;ko&quot; 
      xmlns:th=&quot;http://www.thymeleaf.org&quot;
      xmlns:layout=&quot;http://www.ultraq.net.nz/thymeleaf/layout&quot;&amp;gt;
&amp;lt;body&amp;gt;
  	//전체 레이아웃
	&amp;lt;th:block th:fragment=&quot;headerFg&quot;&amp;gt;
 	&amp;lt;/th:block&amp;gt;
&amp;lt;/body&amp;gt;  
  
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;block은 타임리프 표현을 어느 곳에서든 사용할 수 있도록 하는 구문&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;해당 기능은 동적인 처리가 필요할 때 사용되며 주로 layout기능이나 조건부 렌더링 시 사용&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;span style=&quot;color: #006dd7;&quot;&gt;th:fragment&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691426218605&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;body&amp;gt;

&amp;lt;header th:fragment=&quot;headerFg&quot;&amp;gt;
  &amp;lt;p&amp;gt;개발자는 어디까지 공부해야할까?&amp;lt;/p&amp;gt;
&amp;lt;/header&amp;gt;

&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;웹페이지에 메뉴 탭이나 네비게이션바와 같이 공통으로 반복되는 영역이 존재한다. 이 공통의 역영들을 매 페이지마다 HTML코드를 반복해서 쓰면 굉장히 지저분 해지는데&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;fragment가 바로 공통 영역을 정의&lt;/b&gt;하여 코드를 정리해준다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;특히, header와 footer에 삽입하여 조각화 한다. 이렇게 만들어진 조각을 삽입하고자 하는 대상 HTML 파일에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;th:replace&quot;[파일경로 :: 조각 이름]&quot;&lt;/b&gt;을 통해 삽입한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;nbsp;th:if=&quot;${}&quot;,&amp;nbsp;th:unless=&quot;${}&quot;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691426434382&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;span th:if=&quot;${temp} == 바보&quot;&amp;gt;&amp;lt;/span&amp;gt; 
&amp;lt;span th:unless=&quot;${temp} == 바보&quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;if 와 else로 이해하면 된다. &lt;b&gt;조건&lt;/b&gt;이 성립하지 않으면 렌더링 되지 않는다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;th:switch,&amp;nbsp;th:case&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691426548910&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;th:block th:switch=&quot;${userAuth}&quot;&amp;gt; 
  &amp;lt;span th:case=&quot;1&quot;&amp;gt;관리자&amp;lt;/span&amp;gt; 
  &amp;lt;span th:case=&quot;2&quot;&amp;gt;사용자&amp;lt;/span&amp;gt; 
&amp;lt;/th:block&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;switch case 문과 동일하고 마찬가지로 &lt;b&gt;조건&lt;/b&gt;이 성립하지 않으면 렌더링 되지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p 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;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;진행상황&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서버에서 받아온 데이터를 통해 동적 HTML 처리 완료&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&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;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;업무 중 이슈/고민 또는 해결 내용&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&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;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.thymeleaf.org/documentation.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.thymeleaf.org/documentation.html&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691417635587&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Documentation - Thymeleaf&quot; data-og-description=&quot;Articles Quick glimpses into what Thymeleaf can bring to your project. Introductions With Spring Comparisons&quot; data-og-host=&quot;www.thymeleaf.org&quot; data-og-source-url=&quot;https://www.thymeleaf.org/documentation.html&quot; data-og-url=&quot;https://www.thymeleaf.org/documentation.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.thymeleaf.org/documentation.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.thymeleaf.org/documentation.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Documentation - Thymeleaf&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Articles Quick glimpses into what Thymeleaf can bring to your project. Introductions With Spring Comparisons&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.thymeleaf.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://catsbi.oopy.io/32a9458e-f452-4733-b87c-caba75f98e2d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://catsbi.oopy.io/32a9458e-f452-4733-b87c-caba75f98e2d&lt;/a&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;(출처 : catsbi 님)&lt;/p&gt;
&lt;figure id=&quot;og_1691423963048&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;1. 타임리프 - 기본 기능&quot; data-og-description=&quot;목차&quot; data-og-host=&quot;catsbi.oopy.io&quot; data-og-source-url=&quot;https://catsbi.oopy.io/32a9458e-f452-4733-b87c-caba75f98e2d&quot; data-og-url=&quot;https://catsbi.oopy.io/32a9458e-f452-4733-b87c-caba75f98e2d&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/byKch4/hyTAuyvkCm/UwNz8kFtYW9yJnMzEyqzjK/img.png?width=2000&amp;amp;height=1204&amp;amp;face=0_0_2000_1204,https://scrap.kakaocdn.net/dn/bYSTuw/hyTzkdb0WK/1orBZ9Ohz3LOW2viENHVQk/img.png?width=2000&amp;amp;height=1204&amp;amp;face=0_0_2000_1204,https://scrap.kakaocdn.net/dn/bAsihu/hyTADWwht8/g709otPFzdj6YdTfp2fcOK/img.png?width=2000&amp;amp;height=875&amp;amp;face=0_0_2000_875&quot;&gt;&lt;a href=&quot;https://catsbi.oopy.io/32a9458e-f452-4733-b87c-caba75f98e2d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://catsbi.oopy.io/32a9458e-f452-4733-b87c-caba75f98e2d&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/byKch4/hyTAuyvkCm/UwNz8kFtYW9yJnMzEyqzjK/img.png?width=2000&amp;amp;height=1204&amp;amp;face=0_0_2000_1204,https://scrap.kakaocdn.net/dn/bYSTuw/hyTzkdb0WK/1orBZ9Ohz3LOW2viENHVQk/img.png?width=2000&amp;amp;height=1204&amp;amp;face=0_0_2000_1204,https://scrap.kakaocdn.net/dn/bAsihu/hyTADWwht8/g709otPFzdj6YdTfp2fcOK/img.png?width=2000&amp;amp;height=875&amp;amp;face=0_0_2000_875');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;1. 타임리프 - 기본 기능&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;catsbi.oopy.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;글을 읽어주셔서 감사합니다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; 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;</description>
      <category>Develop/Back-End</category>
      <category>spring thymeleaf</category>
      <category>thymeleaf</category>
      <category>Thymeleaf 구문</category>
      <category>Thymeleaf 문법</category>
      <category>타임리프</category>
      <category>타임리프 문법</category>
      <category>타임리프 사용방법</category>
      <category>타임리프 사용법</category>
      <category>타임리프 어떻게 사용하는거야</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/17</guid>
      <comments>https://djlife.tistory.com/17#entry17comment</comments>
      <pubDate>Tue, 8 Aug 2023 01:46:20 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 스트림(Stream) API 사용 방법 / 외부반복 내부반복 차이점</title>
      <link>https://djlife.tistory.com/16</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드.jpg&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lksYc/btsp9qMn7Cf/FxzngWwCocKaeKIU7PAJN0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lksYc/btsp9qMn7Cf/FxzngWwCocKaeKIU7PAJN0/img.jpg&quot; data-alt=&quot;&amp;amp;lt;image by toptal&amp;amp;gt;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lksYc/btsp9qMn7Cf/FxzngWwCocKaeKIU7PAJN0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlksYc%2Fbtsp9qMn7Cf%2FFxzngWwCocKaeKIU7PAJN0%2Fimg.jpg&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;641&quot; height=&quot;640&quot; data-filename=&quot;다운로드.jpg&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;image by toptal&amp;gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 개발자라면 한번쯤 Stream API 에 대해서 들어보게 될 텐데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사 *&lt;b&gt;코드 컨벤션&lt;/b&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;/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;* 코드 컨벤션 (Code Convention)&lt;/b&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;
&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;간단하게 특징과 사용 방법을 블로그에 정리해보려고 해  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림&amp;nbsp;API는&amp;nbsp;자바&amp;nbsp;8부터&amp;nbsp;추가된&amp;nbsp;기능이야.&amp;nbsp;이걸&amp;nbsp;쓰면&amp;nbsp;컬렉션&amp;nbsp;처리가&amp;nbsp;훨씬&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;구성돼&amp;nbsp;있는데,&amp;nbsp;중간&amp;nbsp;연산은&amp;nbsp;데이터를&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;API를&amp;nbsp;사용하면&amp;nbsp;코드가&amp;nbsp;짧아지고&amp;nbsp;병렬&amp;nbsp;처리도&amp;nbsp;자동으로&amp;nbsp;지원되어&amp;nbsp;멀티코어&amp;nbsp;CPU를&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;좋아지는거지. &lt;br /&gt;&lt;br /&gt;간단한 예시를 보여줄게.  &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691173621893&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Arrays;
import java.util.List;

public class StreamApiExample {
    public static void main(String[] args) {
        List&amp;lt;String&amp;gt; names = Arrays.asList(&quot;Alice&quot;, &quot;Bob&quot;, &quot;Charlie&quot;, &quot;David&quot;, &quot;Emma&quot;);

        // 이름이 4글자 이상인 요소만 필터링하여 새로운 리스트 생성
        List&amp;lt;String&amp;gt; longNames = names.stream()
                .filter(name -&amp;gt; name.length() &amp;gt;= 4)
                .toList();

        System.out.println(&quot;4글자 이상인 이름들: &quot; + longNames);

        // 각 이름을 대문자로 변환하여 새로운 리스트 생성
        List&amp;lt;String&amp;gt; upperCaseNames = names.stream()
                .map(String::toUpperCase)
                .toList();

        System.out.println(&quot;대문자로 변환된 이름들: &quot; + upperCaseNames);

        // 모든 이름을 하나의 문자열로 합치기
        String allNames = names.stream()
                .reduce((name1, name2) -&amp;gt; name1 + &quot;, &quot; + name2)
                .orElse(&quot;&quot;);

        System.out.println(&quot;모든 이름: &quot; + allNames);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이렇게&amp;nbsp;스트림&amp;nbsp;API를&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;글 가장 하단 참고 영역에 오라클 Document 링크도 남겨놓았으니&lt;/p&gt;
&lt;p 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;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내부반복과 외부반복&lt;/b&gt;  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;1.&amp;nbsp;내부반복&amp;nbsp;(Internal&amp;nbsp;Iteration):&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;내부반복은&amp;nbsp;&lt;span style=&quot;color: #409d00;&quot;&gt;Stream&amp;nbsp;API&lt;/span&gt;가 컬렉션의 요소를 내부적으로 처리하는 방식으로, 개발자는 요소 반복을 명시적으로 작성하지 않아. 이를 통해 개발자는 데이터 처리에 집중할 수 있지&lt;br /&gt;&lt;br /&gt;&lt;b&gt;장점:&lt;/b&gt; &lt;br /&gt;- 간결하고 가독성이 높은 코드 작성이 가능&lt;br /&gt;- 병렬 처리를 자동으로 지원하므로 멀티코어 CPU에서 병렬 실행 활용&lt;br /&gt;&lt;br /&gt;&lt;b&gt;단점:&lt;/b&gt; &lt;br /&gt;- 커스텀 반복 로직을 작성하기 어렵거나 제약이 있음&lt;br /&gt;- 간혹 복잡한 연산에서는 성능이 약간 저하&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691172530975&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; numbers = Arrays.asList(1, 2, 3, 4, 5);

// 내부반복으로 짝수인 숫자들을 필터링하여 총합 구하기
int sumOfEvenNumbers = numbers.stream()
        .filter(number -&amp;gt; number % 2 == 0)
        .mapToInt(Integer::intValue)
        .sum();

System.out.println(&quot;짝수의 합: &quot; + sumOfEvenNumbers);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.&amp;nbsp;외부반복&amp;nbsp;(External&amp;nbsp;Iteration):&lt;/b&gt; &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;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;개발자가&amp;nbsp;반복&amp;nbsp;로직을&amp;nbsp;명시적으로&amp;nbsp;작성해야해. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;장점&lt;/b&gt;: &lt;br /&gt;- 커스텀 반복 로직을 자유롭게 작성할 수 있음&lt;br /&gt;- 코드의 동작을 직접 제어하고 디버깅하기 쉬움&lt;br /&gt;&lt;br /&gt;&lt;b&gt;단점&lt;/b&gt;: &lt;br /&gt;- 코드가 비교적 길고 복잡해질 수 있음&lt;br /&gt;- 병렬 처리를 구현하기 어려우며, 멀티코어 CPU의 성능을 최대한 활용하기 어려움&lt;br /&gt;&lt;br /&gt;예시:&lt;/p&gt;
&lt;pre id=&quot;code_1691172550262&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; numbers = Arrays.asList(1, 2, 3, 4, 5);

// 외부반복으로 짝수인 숫자들을 필터링하여 총합 구하기
int sumOfEvenNumbers = 0;
for (Integer number : numbers) {
    if (number % 2 == 0) {
        sumOfEvenNumbers += number;
    }
}

System.out.println(&quot;짝수의 합: &quot; + sumOfEvenNumbers);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;결론적으로, 내부반복은 간결하고 성능 개선을 기대할 수 있고  ,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;반면 외부반복은 커스텀 로직 작성이 자유롭고 직관적인 디버깅이 가능해&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;선택은 개발 상황과 선호에 따라 달라질 수 있고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Stream API를 잘 활용하면 더 간결하고 효율적인 코드를 작성할 수 있을거야&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; 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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691171108492&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;java.util.stream (Java Platform SE 8 )&quot; data-og-description=&quot;Interface Summary&amp;nbsp; Interface Description BaseStream &amp;gt; Base interface for streams, which are sequences of elements supporting sequential and parallel aggregate operations. Collector A mutable reduction operation that accumulates input elements into a mutab&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html&quot; data-og-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;java.util.stream (Java Platform SE 8 )&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Interface Summary&amp;nbsp; Interface Description BaseStream &amp;gt; Base interface for streams, which are sequences of elements supporting sequential and parallel aggregate operations. Collector A mutable reduction operation that accumulates input elements into a mutab&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.baeldung.com/java-8-streams-introduction&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.baeldung.com/java-8-streams-introduction&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691171108492&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;java.util.stream (Java Platform SE 8 )&quot; data-og-description=&quot;Interface Summary&amp;nbsp; Interface Description BaseStream &amp;gt; Base interface for streams, which are sequences of elements supporting sequential and parallel aggregate operations. Collector A mutable reduction operation that accumulates input elements into a mutab&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://www.baeldung.com/java-8-streams-introduction&quot; data-og-url=&quot;https://www.baeldung.com/java-8-streams-introduction&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.baeldung.com/java-8-streams-introduction&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.baeldung.com/java-8-streams-introduction&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://miro.medium.com/v2/resize:fit:600/1*UWLR9XgcVbjI8ebYIeKh_Q.png');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;The Baeldung&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Introduction to Java 8 Streams&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.baeldung.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>backend</category>
      <category>Developer</category>
      <category>Java</category>
      <category>Stream</category>
      <category>Stream API</category>
      <category>개발자</category>
      <category>백엔드 개발자</category>
      <category>스트림</category>
      <category>자바</category>
      <category>자바 스트림 사용방법</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/16</guid>
      <comments>https://djlife.tistory.com/16#entry16comment</comments>
      <pubDate>Sat, 5 Aug 2023 03:29:31 +0900</pubDate>
    </item>
    <item>
      <title>dropzone.js 를 이용하여 동영상 업로드  미리보기  및 썸네일  기능 구현기</title>
      <link>https://djlife.tistory.com/15</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;60432400-6ae5-11eb-8a34-61cced90584a.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSTO7v/btspVpmxqtw/hzKI6jrBP0TxtRjIYvB5N0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSTO7v/btspVpmxqtw/hzKI6jrBP0TxtRjIYvB5N0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSTO7v/btspVpmxqtw/hzKI6jrBP0TxtRjIYvB5N0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSTO7v%2FbtspVpmxqtw%2FhzKI6jrBP0TxtRjIYvB5N0%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;1280&quot; height=&quot;640&quot; data-filename=&quot;60432400-6ae5-11eb-8a34-61cced90584a.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 내가 맡게 된 업무는 dropzone.js 를 이용하여 동영상 업로드와 미리보기 및 썸네일 기능을 만드는 것이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘들어 부쩍 스크립트 만질 일이 많아졌는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BE 코드를 다루지 못하고 있어서 아쉬움이 많다...  &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;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업무 진행 당시 dropzone.js version : 5.5.0&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;진행상황&lt;/b&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이슈 &amp;amp; 고민 및 해결&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;배너배리에이션 기능을 만들었던 이미지 등록하는 화면에서&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;당시에는 발견하지 못했던 버그들도 발견하면서 수정하고 dropzone.js 오픈 소스 라이브러리 코어 스크립트를 조금&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;수정하였다.  &lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 업무를 진행하면서 이슈나 고민 거리는 없었던 것 같다  &lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;[지난 배너 배레이이션 작업 이후 체크 못한 결함 사항 수정 리스트  ]&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1.&amp;nbsp;250*250&amp;nbsp;소재&amp;nbsp;업로드&amp;nbsp;후&amp;nbsp;250*250&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;250*250&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;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;수정)&lt;br /&gt;2. 미리보기 표출 좌표 계산식 수정 ( 표출하는 영역 높이에 따라 미리보기 이미지들이 잘려서 안보일 수 있으므로 계산식을 통해 표출하는 위치를 조정)&lt;br /&gt;&amp;nbsp;&amp;nbsp;-&amp;gt;&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;as-is&amp;nbsp;&amp;nbsp;preveiw&amp;nbsp;element&amp;nbsp;y&amp;nbsp;좌표&amp;nbsp;+&amp;nbsp;preveiw&amp;nbsp;높이&amp;nbsp;&amp;gt;&amp;nbsp;상위&amp;nbsp;element&amp;nbsp;높이&lt;br /&gt;&amp;nbsp;&amp;nbsp;to-be&amp;nbsp;preview&amp;nbsp;높이&amp;nbsp;+&amp;nbsp;preview&amp;nbsp;바닥&amp;nbsp;좌표&amp;nbsp;+&amp;nbsp;&amp;nbsp;이미지&amp;nbsp;높이&amp;nbsp;+&amp;nbsp;이미지&amp;nbsp;바닥&amp;nbsp;좌표&amp;nbsp;&amp;nbsp;&amp;gt;&amp;nbsp;상위&amp;nbsp;element&amp;nbsp;높이&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 기존 홀로그램 배너 수정 시 데이터 값 표출 누락 수정&lt;br /&gt;&lt;br /&gt;[dropzone core script 동영상 업로드 가능하도록 커스터마이징]&lt;br /&gt;***&amp;nbsp;el로&amp;nbsp;유효성&amp;nbsp;모두&amp;nbsp;판단&amp;nbsp;***&lt;br /&gt;1.&amp;nbsp;addedfile&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;1-1.&amp;nbsp;el&amp;nbsp;생성&amp;nbsp;및&amp;nbsp;이벤트&lt;br /&gt;2. dropzone.js videoUploadSucess, videoUploadFail 이벤트 리스너 추가 ( 동영상 업로드 이후 무해화 로직 , 실패 시 화면에 처리할 로직 추가 )&lt;br /&gt;3. 썸네일 추출 ( 영상 특정 구간 캔버스로 변환 후 사진 추출 ) - 지난 업무 중 배너 배리에이션 기능을 만들면서&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;캔버스에 조금 익숙해져서 바로 생각나서 기능을 만들었던 것 같다,   (&lt;a title=&quot;캔버스 API 도전기&quot; href=&quot;https://djlife.tistory.com/13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;캔버스 API 도전기&lt;/a&gt;)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.dropzone.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.dropzone.dev/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690983809537&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Dropzone.js&quot; data-og-description=&quot;Dropzone.js is an open source library that provides beautiful and easy to use drag'n'drop file uploads with image previews.&quot; data-og-host=&quot;www.dropzone.dev&quot; data-og-source-url=&quot;https://www.dropzone.dev/&quot; data-og-url=&quot;https://www.dropzone.dev/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cUKaGI/hyTwjq2fck/KeY740JNxNP9vU6aD5KhD0/img.jpg?width=1920&amp;amp;height=800&amp;amp;face=0_0_1920_800&quot;&gt;&lt;a href=&quot;https://www.dropzone.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.dropzone.dev/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cUKaGI/hyTwjq2fck/KeY740JNxNP9vU6aD5KhD0/img.jpg?width=1920&amp;amp;height=800&amp;amp;face=0_0_1920_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Dropzone.js&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Dropzone.js is an open source library that provides beautiful and easy to use drag'n'drop file uploads with image previews.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.dropzone.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://github.com/dropzone/dropzone&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/dropzone/dropzone&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690983821603&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - dropzone/dropzone: Dropzone is an easy to use drag'n'drop library. It supports image previews and shows nice progress b&quot; data-og-description=&quot;Dropzone is an easy to use drag'n'drop library. It supports image previews and shows nice progress bars. - GitHub - dropzone/dropzone: Dropzone is an easy to use drag'n'drop library...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/dropzone/dropzone&quot; data-og-url=&quot;https://github.com/dropzone/dropzone&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cnvqli/hyTwq4LHHU/HdswLWnRhLHNOdkXu0ekFk/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640&quot;&gt;&lt;a href=&quot;https://github.com/dropzone/dropzone&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/dropzone/dropzone&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cnvqli/hyTwq4LHHU/HdswLWnRhLHNOdkXu0ekFk/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - dropzone/dropzone: Dropzone is an easy to use drag'n'drop library. It supports image previews and shows nice progress b&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Dropzone is an easy to use drag'n'drop library. It supports image previews and shows nice progress bars. - GitHub - dropzone/dropzone: Dropzone is an easy to use drag'n'drop library...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://developer.mozilla.org/ko/docs/Web/JavaScript&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691025379252&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;JavaScript | MDN&quot; data-og-description=&quot;JavaScript (JS)는 가벼운, 인터프리터 혹은 just-in-time 컴파일 프로그래밍 언어로, 일급 함수를 지원합니다. 웹 페이지를 위한 스크립트 언어로 잘 알려져 있지만, Node.js, Apache CouchDB, Adobe Acrobat처럼 &quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript&quot; data-og-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cp3j3u/hyTwmuSsh7/7oddk851CxnAUk7f15Y5b1/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cp3j3u/hyTwmuSsh7/7oddk851CxnAUk7f15Y5b1/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JavaScript | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;JavaScript (JS)는 가벼운, 인터프리터 혹은 just-in-time 컴파일 프로그래밍 언어로, 일급 함수를 지원합니다. 웹 페이지를 위한 스크립트 언어로 잘 알려져 있지만, Node.js, Apache CouchDB, Adobe Acrobat처럼&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TO DO List&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 단위테스트&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 코드 리팩토링 (불필요 코드 제거 개발 중 디버깅 콘솔 로그 제거,변수명 정리)(FE,BE)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example Code&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dropzone.js core 파일 추가 이벤트에 파일 타입이 영상 일 때 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 이벤트 리스너에 &quot;videoUploadSucess&quot;,&quot;videoUploadFail&quot; 이벤트 추가&lt;/p&gt;
&lt;pre id=&quot;code_1691025048436&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;this.prototype.events = [&quot;drop&quot;, &quot;dragstart&quot;, &quot;dragend&quot;, &quot;dragenter&quot;, &quot;dragover&quot;, &quot;dragleave&quot;, &quot;addedfile&quot;, &quot;addedfiles&quot;, &quot;removedfile&quot;, &quot;thumbnail&quot;, &quot;error&quot;, &quot;errormultiple&quot;, &quot;processing&quot;, &quot;processingmultiple&quot;, &quot;uploadprogress&quot;, &quot;totaluploadprogress&quot;, &quot;sending&quot;, &quot;sendingmultiple&quot;, &quot;success&quot;, &quot;successmultiple&quot;, &quot;canceled&quot;, &quot;canceledmultiple&quot;, &quot;complete&quot;, &quot;completemultiple&quot;, &quot;reset&quot;, &quot;maxfilesexceeded&quot;, &quot;maxfilesreached&quot;, &quot;queuecomplete&quot;,&quot;videoUploadSucess&quot;,&quot;videoUploadFail&quot;];
....
....
....
addedfile: function addedfile(file) {
                    console.log(&quot;process core&quot;);
                    var _this2 = this;

                    if (this.element === this.previewsContainer) {
                        this.element.classList.add(&quot;dz-started&quot;);
                    }

                    if (this.previewsContainer) {
                        file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim());
                        file.previewTemplate = file.previewElement; // Backwards compatibility
                        if (this.options.previewArea === null) {
                            if (file.type === &quot;video/mp4&quot;){
                                var _obj = {&quot;title&quot; : &quot;&quot; , &quot;code&quot; : &quot;&quot; ,&quot;titleEng&quot; : &quot;&quot; , &quot;imageSize&quot; : &quot;&quot;};
                                var vidUrl = window.URL.createObjectURL(file);

                               if(file.name === &quot;width.mp4&quot;){
                                    _obj[&quot;title&quot;] = &quot;가로형&quot;;
                                    _obj[&quot;code&quot;] = &quot;96&quot;;
                                    _obj[&quot;titleEng&quot;] = &quot;width&quot;;
                                    _obj[&quot;imageSize&quot;] = &quot;VIDEO_WIDTH&quot;;
                                }else if(file.name === &quot;length.mp4&quot;){
                                    _obj[&quot;title&quot;] = &quot;세로형&quot;;
                                    _obj[&quot;code&quot;] = &quot;97&quot;;
                                    _obj[&quot;titleEng&quot;] = &quot;length&quot;;
                                    _obj[&quot;imageSize&quot;] = &quot;VIDEO_HEIGHT&quot;;
                                }else if(file.name === &quot;square.mp4&quot;){
                                    _obj[&quot;title&quot;] = &quot;사각형&quot;;
                                    _obj[&quot;code&quot;] = &quot;98&quot;;
                                    _obj[&quot;titleEng&quot;] = &quot;square&quot;;
                                    _obj[&quot;imageSize&quot;] = &quot;VIDEO_SQUARE&quot;;
                                }

                                if($(`#div_${_obj[&quot;titleEng&quot;]}`).length &amp;gt; 0){
                                    return this.emit(&quot;videoUploadFail&quot;, file , &quot;동일파일 이슈&quot;);
                                    return false;
                                }else if(file.size &amp;gt; 5242880){
                                    return this.emit(&quot;videoUploadFail&quot;, file , &quot;용량 이슈&quot;);
                                    return false;
                                }

                                var _div = document.createElement('div');
                                    _div.className = &quot;imgItem&quot;;
                                    _div.id = `div_${_obj[&quot;titleEng&quot;]}`;
                                    _div.dataset.title = _obj[&quot;title&quot;];
                                    _div.dataset.code = _obj[&quot;code&quot;];
                                    _div.dataset.titleEng = _obj[&quot;titleEng&quot;];
                                    _div.dataset.imageSize = _obj[&quot;imageSize&quot;];

                                    _div.innerHTML = `&amp;lt;button type=&quot;button&quot; class=&quot;ico-close-gray&quot; onclick=&quot;deleteVideoItem(this)&quot; &amp;gt;&amp;lt;/button&amp;gt;
                                                      	&amp;lt;div class=&quot;videoBox&quot;&amp;gt;
                                                      		&amp;lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; width=&quot;181px&quot; height=&quot;120px&quot;&amp;gt;
                                                      			&amp;lt;source src=${vidUrl}&amp;gt;
                                                      		&amp;lt;/video&amp;gt;
                                                      	&amp;lt;/div&amp;gt;
                                                      	&amp;lt;div class=&quot;textBox&quot;&amp;gt;
                                                      		&amp;lt;em&amp;gt;[PC/M]&amp;lt;/em&amp;gt;
                                                      		&amp;lt;p&amp;gt;${_obj[&quot;title&quot;]}&amp;lt;/p&amp;gt;
                                                      		&amp;lt;button type=&quot;button&quot; class=&quot;btn-ss btn-gray-line&quot; onclick=&quot;previewVideoItem(this)&quot;&amp;gt;미리보기&amp;lt;/button&amp;gt;
                                                      	&amp;lt;/div&amp;gt;`;

                                if(file.name !== &quot;width.mp4&quot; &amp;amp;&amp;amp; file.name !== &quot;length.mp4&quot; &amp;amp;&amp;amp; file.name !== &quot;square.mp4&quot;){
                                    return this.emit(&quot;videoUploadFail&quot;, file , &quot;파일명 이슈&quot;);
                                    return false;
                                }

                                document.getElementById(&quot;mobonVideoUpload&quot;).appendChild(_div);
                                file.previewElement = _div;
                                return this.emit(&quot;videoUploadSucess&quot;, file);
                            }else{
                                document.getElementById(&quot;mobonImageUpload&quot;).appendChild(file.previewElement);
                            }
                        } else {
                            this.options.previewArea.appendChild(file.previewElement);
                        }
                        for (var _iterator3 = file.previewElement.querySelectorAll(&quot;[data-dz-name]&quot;), _isArray3 = true, _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
                            var _ref3;

                            if (_isArray3) {
                                if (_i3 &amp;gt;= _iterator3.length) break;
                                _ref3 = _iterator3[_i3++];
                            } else {
                                _i3 = _iterator3.next();
                                if (_i3.done) break;
                                _ref3 = _i3.value;
                            }

                            var node = _ref3;

                            node.textContent = file.name;
                        }
                        for (var _iterator4 = file.previewElement.querySelectorAll(&quot;[data-dz-size]&quot;), _isArray4 = true, _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) {
                            if (_isArray4) {
                                if (_i4 &amp;gt;= _iterator4.length) break;
                                node = _iterator4[_i4++];
                            } else {
                                _i4 = _iterator4.next();
                                if (_i4.done) break;
                                node = _i4.value;
                            }

                            node.innerHTML = this.filesize(file.size);
                        }

                        if (this.options.addRemoveLinks) {
                            //file._removeLink = Dropzone.createElement(&quot;&amp;lt;a class=\&quot;dz-remove\&quot; href=\&quot;javascript:undefined;\&quot; data-dz-remove&amp;gt;&quot; + this.options.dictRemoveFile + &quot;&amp;lt;/a&amp;gt;&quot;);
							file._removeLink = Dropzone.createElement(&quot;&amp;lt;a class=\&quot;dz-remove btn-del\&quot; href=\&quot;javascript:undefined;\&quot; class=\&quot;btn-del\&quot; data-dz-remove&amp;gt;삭제&amp;lt;/a&amp;gt;&quot;);
                            file.previewElement.appendChild(file._removeLink);
                        }

                        var removeFileEvent = function removeFileEvent(e) {
                            e.preventDefault();
                            e.stopPropagation();
                            if (file.status === Dropzone.UPLOADING) {
                                return Dropzone.confirm(_this2.options.dictCancelUploadConfirmation, function () {
                                    return _this2.removeFile(file);
                                });
                            } else {
                                if (_this2.options.dictRemoveFileConfirmation) {
                                    return Dropzone.confirm(_this2.options.dictRemoveFileConfirmation, function () {
                                        return _this2.removeFile(file);
                                    });
                                } else {
                                    return _this2.removeFile(file);
                                }
                            }
                        };

                        for (var _iterator5 = file.previewElement.querySelectorAll(&quot;[data-dz-remove]&quot;), _isArray5 = true, _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) {
                            var _ref4;

                            if (_isArray5) {
                                if (_i5 &amp;gt;= _iterator5.length) break;
                                _ref4 = _iterator5[_i5++];
                            } else {
                                _i5 = _iterator5.next();
                                if (_i5.done) break;
                                _ref4 = _i5.value;
                            }

                            var removeLink = _ref4;

                            removeLink.addEventListener(&quot;click&quot;, removeFileEvent);
                        }
                    }
                }
...
...
...
videoUploadSucess: function videoUploadSucess(file){},
videoUploadFail: function videoUploadFail(file,errMsg){},

...
...
...
function deleteVideoItem(element) {
    element.parentElement.remove();
}

function previewVideoItem(element){
 var videoSrc = $(element).parent().siblings('.videoBox').find(&quot;video &amp;gt; source&quot;).attr('src');
 $(element).parent().parent().append(&quot;&amp;lt;div class='videoWrap'&amp;gt;&amp;lt;video class='model-vid' autoplay controls loop muted width='100%' height='100%'&amp;gt;&amp;lt;source src='&quot; + videoSrc + &quot;' type='video/mp4'&amp;gt;&amp;lt;/source&amp;gt;&amp;lt;/video&amp;gt;&amp;lt;/div&amp;gt;&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&amp;nbsp; &lt;br /&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;캔버스 API를 이용해 동영상 특정 구간을 캔버스에 그린 후 base64 로 인코딩하여 작업하였다.  &lt;/p&gt;
&lt;pre id=&quot;code_1691026948419&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;         this.on(&quot;videoUploadFail&quot;, function (file,errMsg) {
                    console.debug(&quot;videoUploadFail&quot;, file);
                    alert(&quot;업로드 파일을 다시 한 번 확인해 주세요. \n가로형 : width.mp4\n세로형 : length.mp4\n사각형 : square.mp4&quot;);

                    var video = document.createElement(&quot;video&quot;);
                        video.style.width = &quot;80px&quot;;
                        video.style.height = &quot;80px&quot;;

                    var source = document.createElement(&quot;source&quot;);
                        source.src = window.URL.createObjectURL(file);

                    video.appendChild(source);

                    var thumbnailCanvas = document.createElement(&quot;canvas&quot;);
                        thumbnailCanvas.width = 180;
                        thumbnailCanvas.height = 180;

                    var ctx = thumbnailCanvas.getContext(&quot;2d&quot;);

                    // 'loadedmetadata' 이벤트를 등록하고, 이벤트가 한 번만 실행되도록 함
                    video.addEventListener(&quot;loadedmetadata&quot;, function () {
                        video.currentTime = 1; // 원하는 시간(초)으로 이동
                    }, { once: true });

                    video.addEventListener(&quot;seeked&quot;, function () {
                        ctx.drawImage(video, 0, 0, thumbnailCanvas.width, thumbnailCanvas.height);
                        var thumbnailURL = thumbnailCanvas.toDataURL();

                        var failEl = document.createElement(&quot;div&quot;);
                        failEl.className = &quot;imgItem noimg&quot;;
                        //&amp;lt;button type=&quot;button&quot; class=&quot;ico-none ico-close-gray&quot;&amp;gt;&amp;lt;/button&amp;gt;
                        failEl.innerHTML = `&amp;lt;img src=&quot;${thumbnailURL}&quot; width=&quot;180px&quot; height=&quot;180px&quot;&amp;gt;
                                                &amp;lt;div class=&quot;textBox&quot;&amp;gt;
                                                    &amp;lt;p style=&quot;overflow-x: hidden;&quot;&amp;gt;${file.name}&amp;lt;/p&amp;gt;
                                                &amp;lt;/div&amp;gt;
                                                &amp;lt;div class=&quot;errorLabel error_type01&quot;&amp;gt;
                                                    &amp;lt;i&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;span&amp;gt;${errMsg}&amp;lt;/span&amp;gt;
                                                &amp;lt;/div&amp;gt;
                                            `;
                        document.getElementById(&quot;videoFailContainer&quot;).innerHTML=&quot;&quot;;
                        document.getElementById(&quot;videoFailContainer&quot;).appendChild(failEl);
                        myDropzone.removeFile(file);
                    }, { once: true });
                    video.load();
                });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Front-End</category>
      <category>dropzone.js</category>
      <category>JavaScript</category>
      <category>javascript custom</category>
      <category>동영상 썸네일</category>
      <category>동영상 업로드</category>
      <category>드랍존 js</category>
      <category>미리보기</category>
      <category>썸네일</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/15</guid>
      <comments>https://djlife.tistory.com/15#entry15comment</comments>
      <pubDate>Wed, 2 Aug 2023 23:45:16 +0900</pubDate>
    </item>
    <item>
      <title>난독화 된 자바 스크립트 분석하기</title>
      <link>https://djlife.tistory.com/14</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JavaScript-logo.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ba5POi/btspg094PkO/CHWT1sgcpDbX98qdyxmGy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ba5POi/btspg094PkO/CHWT1sgcpDbX98qdyxmGy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ba5POi/btspg094PkO/CHWT1sgcpDbX98qdyxmGy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fba5POi%2Fbtspg094PkO%2FCHWT1sgcpDbX98qdyxmGy0%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;800&quot; height=&quot;800&quot; data-filename=&quot;JavaScript-logo.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&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;
&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;이해를 하고 다음에 내가 적용할 일이 있으면 그것만큼 값진 경험도 없다고 생각한다. &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;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;역시나 그 행위를 하고 있는게 맞았다... &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;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;진행상황&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;스크립트가 특정 행위를 한다고 예상.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1.기능 예상 시나리오&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2.스크립트 분석 (변수 및 함수 , 전역 변수 용도파악)&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2-1. 특정 조건 파악&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2-2. 데이터 통신 간 요청 데이터 확인 , 응답 데이터 확인&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3.디버깅&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이슈 &amp;amp; 고민 및 해결&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;난독화 된 코드이기도 했지만&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;
&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1690510642185&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 변수 값 대입
var dj = &quot;안녕하세요&quot;;

var life,p;

life = {};
p = &quot;hello Wolrd&quot;;

!life.user_id &amp;amp;&amp;amp; p &amp;amp;&amp;amp; (life.user_id = p);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;life 객체에 키 user_id 값이 undefined 와 nulll 이 아니면 p 값을 대입하는거다.&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;대입시켜놓았다 앞으로 스크립트를 작성할 때 여러 if문을 작성하는게 아니라 이렇게 값을 대입하는 형식&lt;/p&gt;
&lt;p 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;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0055ff;&quot;&gt;&lt;/span&gt;&lt;a href=&quot;http://jsbeautifier.org/&quot;&gt;http://jsbeautifier.org/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690443458589&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Online JavaScript beautifier&quot; data-og-description=&quot;Beautify JavaScript, JSON, React.js, HTML, CSS, SCSS, and SASS&quot; data-og-host=&quot;beautifier.io&quot; data-og-source-url=&quot;http://jsbeautifier.org/&quot; data-og-url=&quot;https://beautifier.io/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;http://jsbeautifier.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://jsbeautifier.org/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Online JavaScript beautifier&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Beautify JavaScript, JSON, React.js, HTML, CSS, SCSS, and SASS&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;beautifier.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0055ff;&quot;&gt;&lt;/span&gt;&lt;a href=&quot;http://dean.edwards.name/unpacker/&quot;&gt;http://dean.edwards.name/unpacker/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690443467268&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;/unpacker/&quot; data-og-description=&quot;This only works in browsers which have a built-in pretty-printer. Copyright &amp;copy; 2004-2023 Dean Edwards. All rights reserved.&quot; data-og-host=&quot;dean.edwards.name&quot; data-og-source-url=&quot;http://dean.edwards.name/unpacker/&quot; data-og-url=&quot;http://dean.edwards.name/unpacker/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;http://dean.edwards.name/unpacker/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://dean.edwards.name/unpacker/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;/unpacker/&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This only works in browsers which have a built-in pretty-printer. Copyright &amp;copy; 2004-2023 Dean Edwards. All rights reserved.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dean.edwards.name&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TO DO List&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 변수에 임의 값 대입&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 디버깅&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 해당 행위 동작하는지 확인&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example Code&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;회사 자산을 함부로 공개 할 수 없어&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다양한 난독화 코드 종류 소개로 대체하겠다&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 이모티콘 난독화(&lt;a href=&quot;https://utf-8.jp/public/aaencode.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://utf-8.jp/public/aaencode.html&lt;/a&gt;)&lt;/p&gt;
&lt;pre id=&quot;code_1690443057637&quot; class=&quot;javascript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;alert(&quot;Hello, dj&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1690445198965&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ﾟ&amp;omega;ﾟﾉ= /｀ｍ&amp;acute;）ﾉ ~┻━┻   //*&amp;acute;&amp;nabla;｀*/ ['_']; o=(ﾟｰﾟ)  =_=3; c=(ﾟ&amp;Theta;ﾟ) =(ﾟｰﾟ)-(ﾟｰﾟ); (ﾟДﾟ) =(ﾟ&amp;Theta;ﾟ)= (o^_^o)/ (o^_^o);(ﾟДﾟ)={ﾟ&amp;Theta;ﾟ: '_' ,ﾟ&amp;omega;ﾟﾉ : ((ﾟ&amp;omega;ﾟﾉ==3) +'_') [ﾟ&amp;Theta;ﾟ] ,ﾟｰﾟﾉ :(ﾟ&amp;omega;ﾟﾉ+ '_')[o^_^o -(ﾟ&amp;Theta;ﾟ)] ,ﾟДﾟﾉ:((ﾟｰﾟ==3) +'_')[ﾟｰﾟ] }; (ﾟДﾟ) [ﾟ&amp;Theta;ﾟ] =((ﾟ&amp;omega;ﾟﾉ==3) +'_') [c^_^o];(ﾟДﾟ) ['c'] = ((ﾟДﾟ)+'_') [ (ﾟｰﾟ)+(ﾟｰﾟ)-(ﾟ&amp;Theta;ﾟ) ];(ﾟДﾟ) ['o'] = ((ﾟДﾟ)+'_') [ﾟ&amp;Theta;ﾟ];(ﾟoﾟ)=(ﾟДﾟ) ['c']+(ﾟДﾟ) ['o']+(ﾟ&amp;omega;ﾟﾉ +'_')[ﾟ&amp;Theta;ﾟ]+ ((ﾟ&amp;omega;ﾟﾉ==3) +'_') [ﾟｰﾟ] + ((ﾟДﾟ) +'_') [(ﾟｰﾟ)+(ﾟｰﾟ)]+ ((ﾟｰﾟ==3) +'_') [ﾟ&amp;Theta;ﾟ]+((ﾟｰﾟ==3) +'_') [(ﾟｰﾟ) - (ﾟ&amp;Theta;ﾟ)]+(ﾟДﾟ) ['c']+((ﾟДﾟ)+'_') [(ﾟｰﾟ)+(ﾟｰﾟ)]+ (ﾟДﾟ) ['o']+((ﾟｰﾟ==3) +'_') [ﾟ&amp;Theta;ﾟ];(ﾟДﾟ) ['_'] =(o^_^o) [ﾟoﾟ] [ﾟoﾟ];(ﾟ&amp;epsilon;ﾟ)=((ﾟｰﾟ==3) +'_') [ﾟ&amp;Theta;ﾟ]+ (ﾟДﾟ) .ﾟДﾟﾉ+((ﾟДﾟ)+'_') [(ﾟｰﾟ) + (ﾟｰﾟ)]+((ﾟｰﾟ==3) +'_') [o^_^o -ﾟ&amp;Theta;ﾟ]+((ﾟｰﾟ==3) +'_') [ﾟ&amp;Theta;ﾟ]+ (ﾟ&amp;omega;ﾟﾉ +'_') [ﾟ&amp;Theta;ﾟ]; (ﾟｰﾟ)+=(ﾟ&amp;Theta;ﾟ); (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]='\\'; (ﾟДﾟ).ﾟ&amp;Theta;ﾟﾉ=(ﾟДﾟ+ ﾟｰﾟ)[o^_^o -(ﾟ&amp;Theta;ﾟ)];(oﾟｰﾟo)=(ﾟ&amp;omega;ﾟﾉ +'_')[c^_^o];(ﾟДﾟ) [ﾟoﾟ]='\&quot;';(ﾟДﾟ) ['_'] ( (ﾟДﾟ) ['_'] (ﾟ&amp;epsilon;ﾟ+(ﾟДﾟ)[ﾟoﾟ]+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ (ﾟｰﾟ)+ (ﾟ&amp;Theta;ﾟ)+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ ((ﾟｰﾟ) + (ﾟ&amp;Theta;ﾟ))+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ (ﾟｰﾟ)+ ((ﾟｰﾟ) + (ﾟ&amp;Theta;ﾟ))+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (ﾟ&amp;Theta;ﾟ))+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ ((o^_^o) +(o^_^o))+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+((ﾟｰﾟ) + (ﾟ&amp;Theta;ﾟ))+ (c^_^o)+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟｰﾟ)+ ((o^_^o) - (ﾟ&amp;Theta;ﾟ))+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ (ﾟ&amp;Theta;ﾟ)+ (c^_^o)+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ (ﾟｰﾟ)+ ((ﾟｰﾟ) + (ﾟ&amp;Theta;ﾟ))+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ ((ﾟｰﾟ) + (ﾟ&amp;Theta;ﾟ))+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ ((ﾟｰﾟ) + (ﾟ&amp;Theta;ﾟ))+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ ((ﾟｰﾟ) + (ﾟ&amp;Theta;ﾟ))+ ((ﾟｰﾟ) + (o^_^o))+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+((ﾟｰﾟ) + (ﾟ&amp;Theta;ﾟ))+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟｰﾟ)+ (c^_^o)+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ (ﾟｰﾟ)+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟ&amp;Theta;ﾟ)+ ((ﾟｰﾟ) + (ﾟ&amp;Theta;ﾟ))+ ((o^_^o) - (ﾟ&amp;Theta;ﾟ))+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+(ﾟｰﾟ)+ ((o^_^o) - (ﾟ&amp;Theta;ﾟ))+ (ﾟДﾟ)[ﾟ&amp;epsilon;ﾟ]+((ﾟｰﾟ) + (ﾟ&amp;Theta;ﾟ))+ (ﾟ&amp;Theta;ﾟ)+ (ﾟДﾟ)[ﾟoﾟ]) (ﾟ&amp;Theta;ﾟ)) ('_');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.hex 형식 난독화(&lt;a href=&quot;https://obfuscator.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://obfuscator.io/&lt;/a&gt;)&lt;/p&gt;
&lt;pre id=&quot;code_1690445291960&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function hi() {
  console.log(&quot;Hello dj!&quot;);
}
hi();&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1690445306429&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(function(_0x6880a2,_0x37c229){var _0x10a19d=_0x15ee,_0x17febb=_0x6880a2();while(!![]){try{var _0x3432e5=-parseInt(_0x10a19d(0x13c))/0x1*(-parseInt(_0x10a19d(0x140))/0x2)+parseInt(_0x10a19d(0x143))/0x3+-parseInt(_0x10a19d(0x142))/0x4*(-parseInt(_0x10a19d(0x13e))/0x5)+-parseInt(_0x10a19d(0x13f))/0x6*(parseInt(_0x10a19d(0x13b))/0x7)+-parseInt(_0x10a19d(0x145))/0x8*(-parseInt(_0x10a19d(0x146))/0x9)+parseInt(_0x10a19d(0x13a))/0xa*(-parseInt(_0x10a19d(0x147))/0xb)+parseInt(_0x10a19d(0x141))/0xc*(-parseInt(_0x10a19d(0x13d))/0xd);if(_0x3432e5===_0x37c229)break;else _0x17febb['push'](_0x17febb['shift']());}catch(_0x1d8892){_0x17febb['push'](_0x17febb['shift']());}}}(_0x301c,0xa9ff6));function hi(){var _0x5a87e7=_0x15ee;console[_0x5a87e7(0x144)]('Hello\x20dj!');}function _0x15ee(_0x431c9a,_0x33cf25){var _0x301c86=_0x301c();return _0x15ee=function(_0x15eecf,_0x2fb7c8){_0x15eecf=_0x15eecf-0x13a;var _0x2c4167=_0x301c86[_0x15eecf];return _0x2c4167;},_0x15ee(_0x431c9a,_0x33cf25);}hi();function _0x301c(){var _0x360e4c=['396608EvcHuJ','27ifKRyY','475277FLfePp','70RLdTio','21LsqitY','69gktPxl','99749dsVcvm','10qIlnRg','1313982mlqaiD','5514rttdTh','120sKtIrN','1956252cGAtEo','1246179bGElqS','log'];_0x301c=function(){return _0x360e4c;};return _0x301c();}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.jjencode (&lt;a href=&quot;https://utf-8.jp/public/jjencode.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://utf-8.jp/public/jjencode.html&lt;/a&gt;)&lt;/p&gt;
&lt;pre id=&quot;code_1690510366499&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;alert(&quot;Hello, Dj&quot; )&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1690510376810&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$한국=~[];$한국={___:++$한국,$$$$:(![]+&quot;&quot;)[$한국],__$:++$한국,$_$_:(![]+&quot;&quot;)[$한국],_$_:++$한국,$_$$:({}+&quot;&quot;)[$한국],$$_$:($한국[$한국]+&quot;&quot;)[$한국],_$$:++$한국,$$$_:(!&quot;&quot;+&quot;&quot;)[$한국],$__:++$한국,$_$:++$한국,$$__:({}+&quot;&quot;)[$한국],$$_:++$한국,$$$:++$한국,$___:++$한국,$__$:++$한국};$한국.$_=($한국.$_=$한국+&quot;&quot;)[$한국.$_$]+($한국._$=$한국.$_[$한국.__$])+($한국.$$=($한국.$+&quot;&quot;)[$한국.__$])+((!$한국)+&quot;&quot;)[$한국._$$]+($한국.__=$한국.$_[$한국.$$_])+($한국.$=(!&quot;&quot;+&quot;&quot;)[$한국.__$])+($한국._=(!&quot;&quot;+&quot;&quot;)[$한국._$_])+$한국.$_[$한국.$_$]+$한국.__+$한국._$+$한국.$;$한국.$$=$한국.$+(!&quot;&quot;+&quot;&quot;)[$한국._$$]+$한국.__+$한국._+$한국.$+$한국.$$;$한국.$=($한국.___)[$한국.$_][$한국.$_];$한국.$($한국.$($한국.$$+&quot;\&quot;&quot;+$한국.$_$_+(![]+&quot;&quot;)[$한국._$_]+$한국.$$$_+&quot;\\&quot;+$한국.__$+$한국.$$_+$한국._$_+$한국.__+&quot;(\\\&quot;\\&quot;+$한국.__$+$한국.__$+$한국.___+$한국.$$$_+(![]+&quot;&quot;)[$한국._$_]+(![]+&quot;&quot;)[$한국._$_]+$한국._$+&quot;,\\&quot;+$한국.$__+$한국.___+&quot;\\&quot;+$한국.__$+$한국.___+$한국.$__+&quot;\\&quot;+$한국.__$+$한국.$_$+$한국._$_+&quot;\\\&quot;\\&quot;+$한국.$__+$한국.___+&quot;)&quot;+&quot;\&quot;&quot;)())();&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Develop/Front-End</category>
      <category>JavaScript</category>
      <category>javascript obfuscation</category>
      <category>Obfuscation</category>
      <category>자바스크립트</category>
      <category>자바스크립트 난독화</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/14</guid>
      <comments>https://djlife.tistory.com/14#entry14comment</comments>
      <pubDate>Fri, 28 Jul 2023 11:22:01 +0900</pubDate>
    </item>
    <item>
      <title>배너배리에이션 기능 - 자바스크립트 캔버스 API 도전기</title>
      <link>https://djlife.tistory.com/13</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;YpEmDFi.jpg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBpPUi/btspeKzXfPM/9gVdHg8ELFMpfDXcW5tyQK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBpPUi/btspeKzXfPM/9gVdHg8ELFMpfDXcW5tyQK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBpPUi/btspeKzXfPM/9gVdHg8ELFMpfDXcW5tyQK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBpPUi%2FbtspeKzXfPM%2F9gVdHg8ELFMpfDXcW5tyQK%2Fimg.jpg&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;1920&quot; height=&quot;1080&quot; data-filename=&quot;YpEmDFi.jpg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;서비스에 없는 기능을 도입하는 것은&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;그동안 내가 개발했던 프로그램들 비중은 주로 BackEnd 영역이다..&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;* &lt;b&gt;배너 배리에이션 : &lt;/b&gt;&amp;nbsp;웹&amp;nbsp;페이지&amp;nbsp;또는&amp;nbsp;앱에서&amp;nbsp;사용되는&amp;nbsp;배너(Banner)나&amp;nbsp;광고&amp;nbsp;영역을&amp;nbsp;다양한&amp;nbsp;스타일로&amp;nbsp;변화시키는&amp;nbsp;기능을&amp;nbsp;말합니다.&amp;nbsp;이는&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;진행상황&lt;/b&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;캔버스(canvasAPI)는 줄바꿈(개행문자) 처리하는 기능이 없기에 이 기능을 만들어야 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이슈 &amp;amp; 고민 및 해결&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기능 개발 중 주로 겪은 고민은&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서버에서 처리 할 지 클라이언트에서 처리 할 지에 대한 고민&lt;/b&gt; 이였다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 고민으로 시간을 소비하던 중 클라이언트에서 처리하는 걸로 결정했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;만든 이미지를 바로 보여주어야 하였고 클라이언트와 서버간 통신이 많아지면 리소스 낭비라고 생각이 들었기 때문이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기존에 파일 업로드 할 때 사용하고 있는 오픈소스 dropzone.js를 이용하고 있었고..&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(해당 코어 스크립트도 파악해야 했다. )&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또 업로드 한 파일을 무해한지 확인하는 솔루션도 이용하고 있었고&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;무해한 파일을 해당 솔루션 서버에 저장하고 내부 서버에서 파일을 다시 가지고 와서 저장하는 방식이였다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;종합적으로 클라이언트에서 처리하는걸로 결정!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또 하나 이슈로는..&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;canvas와 html5 image tag 이미지 로드 방식 차이&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;cors 정책 위반으로 인해 삽질이였는데 ..&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;HTML5 이미지 태그(&amp;lt;img&amp;gt;)를 사용할 때는 보통 CORS(Cross-Origin Resource Sharing) 이슈가 발생하지 않지만&lt;br /&gt;이는 이미지를 불러올 때 브라우저가 이미지 리소스에 대한 CORS 정책을 적용하지 않기 때문이고&lt;br /&gt;그렇기에 다른 호스트에서 가져온 이미지를 &amp;lt;img&amp;gt; 태그를 사용하여 자유롭게 표시할 수 있었고&lt;br /&gt;&lt;br /&gt;반대로, 캔버스(Canvas)를 사용하여 이미지를 로드할 때는 CORS 정책이 적용되어서,&amp;nbsp; &lt;br /&gt;다른 호스트에서 가져온 이미지를 사용할 때 CORS 위배가 발생할 수 있고&amp;nbsp;&amp;nbsp;&lt;br /&gt;이는 보안 상의 이유로 인해 캔버스에서 이미지를 그리는 작업은 기본적으로 CORS 정책을 준수해야 하기 때문에&lt;br /&gt;다른 호스트에서 가져온 이미지를 캔버스에 직접 로드하기 전에 CORS 정책을 설정하거나 서버 측에서 CORS를 허용 설정을 해야되는데.. 내가 이미지를 가지고 올 때는 cdn 리소스 또는 호스트 다른 주소를 가져와야 했고...&lt;br /&gt;&lt;br /&gt;정리하자면,&amp;nbsp;HTML5&amp;nbsp;이미지&amp;nbsp;태그(&amp;lt;img&amp;gt;)는&amp;nbsp;CORS&amp;nbsp;정책을&amp;nbsp;적용하지&amp;nbsp;않아&amp;nbsp;이미지&amp;nbsp;로드에&amp;nbsp;문제가&amp;nbsp;없지만,&amp;nbsp; &lt;br /&gt;캔버스(Canvas)에서 이미지를 로드할 때는 다른 호스트의 리소스를 사용할 때 CORS 정책을 위배할 수 있으니 주의해야 한다... 나 처럼 삽질을 안하려면...  &lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;cors를 우회하기 위해 잔머리를 굴려&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서버에서 이미지를 가지고 오고&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;내부 linux 환경에 이미지가 있을 경우 Backend에서 파일 -&amp;gt;&amp;nbsp; base64 문자열로 encoding 하여&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&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;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 레퍼런스&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690213901699&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Canvas API - Web APIs | MDN&quot; data-og-description=&quot;The Canvas API provides a means for drawing graphics via JavaScript and the HTML &amp;lt;canvas&amp;gt; element. Among other things, it can be used for animation, game graphics, data visualization, photo manipulation, and real-time video processing.&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API&quot; data-og-url=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bjrXjX/hyTqA61FV5/XUu9KE0ABOkuwHIHVMUiUk/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bjrXjX/hyTqA61FV5/XUu9KE0ABOkuwHIHVMUiUk/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Canvas API - Web APIs | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The Canvas API provides a means for drawing graphics via JavaScript and the HTML &amp;lt;canvas&amp;gt; element. Among other things, it can be used for animation, game graphics, data visualization, photo manipulation, and real-time video processing.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;a href=&quot;https://www.w3schools.com/html/html5_canvas.asp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.w3schools.com/html/html5_canvas.asp&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690214064711&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;HTML Canvas&quot; data-og-description=&quot;W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.&quot; data-og-host=&quot;www.w3schools.com&quot; data-og-source-url=&quot;https://www.w3schools.com/html/html5_canvas.asp&quot; data-og-url=&quot;https://www.w3schools.com/html/html5_canvas.asp&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DkBbk/hyTqulqRQ0/WJr1sMm3qfJEj2kksbuEsk/img.png?width=436&amp;amp;height=228&amp;amp;face=0_0_436_228,https://scrap.kakaocdn.net/dn/PO3cr/hyTpc7J1s4/8AQxi9bdQoXuMyerMHMRp0/img.png?width=300&amp;amp;height=599&amp;amp;face=129_253_279_508,https://scrap.kakaocdn.net/dn/zpIqW/hyTqvxRRjR/LSEAl4yBQgXnNjt9mvn8w0/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300&quot;&gt;&lt;a href=&quot;https://www.w3schools.com/html/html5_canvas.asp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.w3schools.com/html/html5_canvas.asp&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DkBbk/hyTqulqRQ0/WJr1sMm3qfJEj2kksbuEsk/img.png?width=436&amp;amp;height=228&amp;amp;face=0_0_436_228,https://scrap.kakaocdn.net/dn/PO3cr/hyTpc7J1s4/8AQxi9bdQoXuMyerMHMRp0/img.png?width=300&amp;amp;height=599&amp;amp;face=129_253_279_508,https://scrap.kakaocdn.net/dn/zpIqW/hyTqvxRRjR/LSEAl4yBQgXnNjt9mvn8w0/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;HTML Canvas&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.w3schools.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cloud.google.com/apigee/docs/api-platform/reference/policies/cors-policy?hl=ko&quot;&gt;https://cloud.google.com/apigee/docs/api-platform/reference/policies/cors-policy?hl=ko&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1690341348326&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;CORS 정책 &amp;nbsp;|&amp;nbsp; Apigee &amp;nbsp;|&amp;nbsp; Google Cloud&quot; data-og-description=&quot;organizations.environments.sharedflows.deployments&quot; data-og-host=&quot;cloud.google.com&quot; data-og-source-url=&quot;https://cloud.google.com/apigee/docs/api-platform/reference/policies/cors-policy?hl=ko&quot; data-og-url=&quot;https://cloud.google.com/apigee/docs/api-platform/reference/policies/cors-policy?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/drTP1u/hyTqxcBnII/mNwKfhZkdmOs5GjKAwPDUk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://cloud.google.com/apigee/docs/api-platform/reference/policies/cors-policy?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cloud.google.com/apigee/docs/api-platform/reference/policies/cors-policy?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/drTP1u/hyTqxcBnII/mNwKfhZkdmOs5GjKAwPDUk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CORS 정책 &amp;nbsp;|&amp;nbsp; Apigee &amp;nbsp;|&amp;nbsp; Google Cloud&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;organizations.environments.sharedflows.deployments&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cloud.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TO DO List&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. &lt;span style=&quot;color: #ee2323;&quot;&gt;개행문자 처리&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 코드 리팩토링 (불필요 코드 제거 개발 중 디버깅 콘솔 로그 제거,변수명 정리)(FE,BE)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example Code&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지를 canvas를 통해 편집하는 function 중 일부&lt;br /&gt;BE코드나 더 자세한 코드는 공개하기 어려워 일부만..&lt;/p&gt;
&lt;pre id=&quot;code_1690214631102&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 이미지 주소를 넣으면 해당 이미지를 이용하여 편집 후 base64로 반환하는 함수
async function resizeImage(imageBase64Url, newTemplate, newWidth, newHeight, idx, callback) {
  // imgnameSchonlogo 로고 , imgnameLogo 앱아이콘 , imgnameFvconlogo 파비콘
  var imgnameFvconlogo, imgnameLogo, imgnameSchonlogo;
  try {

    if (admember != null &amp;amp;&amp;amp; admember != undefined) {
      imgnameFvconlogo = `${serverImageUrl}/ad/imgfile/${admember[&quot;imgnameFvconlogo&quot;]}`;
      imgnameLogo = `${serverImageUrl}/ad/imgfile/${admember[&quot;imgnameLogo&quot;]}`;
      imgnameSchonlogo = `${serverImageUrl}/ad/imgfile/${admember[&quot;imgnameSchonlogo&quot;]}`;
    }

    var canvas = document.createElement('canvas');
    var backGroundImg = document.createElement('img');
        backGroundImg.src = `${imageBase64Url}`;
    var ctx = canvas.getContext('2d');

    async function drawCanvasUtil(_type, _param) {
      if (_type === &quot;backgroundSetting&quot;) {
        ctx.drawImage(backGroundImg, 0, 0, newWidth, newHeight);
      } else if (_type === &quot;backgroundSettingCustom&quot;) {
        ctx.fillStyle = _param[&quot;fillStyle&quot;];
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.drawImage(backGroundImg, _param[&quot;x&quot;], _param[&quot;y&quot;], _param[&quot;width&quot;], _param[&quot;height&quot;]);
      } else if (_type === &quot;backgroundSettingCustom2&quot;) {
        ctx.drawImage(backGroundImg, _param[&quot;imgX&quot;], _param[&quot;imgY&quot;], _param[&quot;imgWidth&quot;], _param[&quot;imgHeight&quot;]);
        ctx.fillStyle = _param[&quot;fillStyle&quot;];
        ctx.fillRect(_param[&quot;x&quot;], _param[&quot;y&quot;], _param[&quot;width&quot;], _param[&quot;height&quot;]);
      } else if (_type === &quot;fillStyle&quot;) {
        ctx.fillStyle = _param[&quot;color&quot;];
      } else if (_type === &quot;copyText&quot; || _type === &quot;Text&quot;) {
        if (_type === &quot;copyText&quot; &amp;amp;&amp;amp; firstCopy === null || firstCopy === undefined) {
          return false;
        }
        ctx.font = _param[&quot;font&quot;];
        ctx.fillStyle = _param[&quot;fillStyle&quot;];
        ctx.textAlign = _param[&quot;textAlign&quot;];
        ctx.textBaseline = _param[&quot;textBaseline&quot;];
        ctx.fillText(_param[&quot;text&quot;], _param[&quot;x&quot;], _param[&quot;y&quot;]);
      } else if (_type === &quot;ctaBtn&quot;) {
        ctx.strokeStyle = _param[&quot;fillStyle&quot;];
        ctx.fillStyle = _param[&quot;fillStyle&quot;];
        ctx.beginPath();
        ctx.roundRect(_param[&quot;x&quot;], _param[&quot;y&quot;], _param[&quot;width&quot;], _param[&quot;height&quot;], _param[&quot;radii&quot;]);
        ctx.stroke();
        ctx.fill();

        ctx.font = _param[&quot;font&quot;];
        ctx.fillStyle = _param[&quot;fontFillStyle&quot;];
        ctx.textAlign = _param[&quot;textAlign&quot;];
        ctx.textBaseline = _param[&quot;textBaseline&quot;];
        ctx.fillText(_param[&quot;text&quot;], _param[&quot;textX&quot;], _param[&quot;textY&quot;]);
      } else if (_type === &quot;drawImage&quot;) {
        return new Promise((resolve, reject) =&amp;gt; {
          var validCheck =  _param[&quot;src&quot;].replace(`${serverImageUrl}/ad/imgfile/`,&quot;&quot;);
          if(validCheck === null || validCheck === undefined || validCheck === &quot;&quot; || validCheck === &quot;null&quot; ){
            resolve();
            return false;
          }

          var additionalImage = new Image();
              additionalImage.crossOrigin = `${serverImageUrl}`;
              additionalImage.onerror = function () {
            console.error(&quot;image load Error&quot;);
            resolve();
          };
          additionalImage.onload = function () {
            ctx.drawImage(additionalImage, _param[&quot;dx&quot;], _param[&quot;dy&quot;], _param[&quot;dWidth&quot;], _param[&quot;dHeight&quot;]);
            //console.debug(`image load complete${_param[&quot;src&quot;]}`);
            resolve();
          };
          additionalImage.src = _param[&quot;src&quot;];
        });
      }
    }

    backGroundImg.onload = async function () {
      if (isNaN(newWidth))
        newWidth = Number(newWidth);
      if (isNaN(newHeight))
        newWidth = Number(newHeight);

      canvas.width = newWidth;
      canvas.height = newHeight;

      switch (newTemplate) {
        case &quot;850x850&quot;:
          await drawCanvasUtil(&quot;backgroundSetting&quot;);
          break;
        case &quot;970x250&quot;:
          await drawCanvasUtil(&quot;backgroundSettingCustom&quot;, { &quot;fillStyle&quot;: &quot;#FFFFFF&quot;, &quot;x&quot;: 0, &quot;y&quot;: 0, &quot;width&quot;: 250, &quot;height&quot;: 250 });
          await drawCanvasUtil(&quot;Text&quot;, { &quot;font&quot;: &quot;bold 25px NotoSansB&quot;, &quot;fillStyle&quot;: &quot;#000000&quot;, &quot;textAlign&quot;: &quot;start&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: admember[&quot;corpname&quot;], &quot;x&quot;: 270, &quot;y&quot;: 91 });
          await drawCanvasUtil(&quot;copyText&quot;, { &quot;font&quot;: &quot;20px NotoSansR&quot;, &quot;fillStyle&quot;: &quot;#000000&quot;, &quot;textAlign&quot;: &quot;start&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: firstCopy[1][&quot;cpComment&quot;], &quot;x&quot;: 270, &quot;y&quot;: 135 });
          await drawCanvasUtil(&quot;ctaBtn&quot;, { &quot;fillStyle&quot;: &quot;#85b74e&quot;, &quot;x&quot;: 745, &quot;y&quot;: 100, &quot;width&quot;: 200, &quot;height&quot;: 50, &quot;radii&quot;: 4, &quot;font&quot;: &quot;18px NotoSansR&quot;, &quot;fontFillStyle&quot;: &quot;#FFFFFF&quot;, &quot;textAlign&quot;: &quot;start&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: &quot;바로가기&quot;, &quot;textX&quot;: 812, &quot;textY&quot;: 125.5 });
          break;
        case &quot;800x1500&quot;:
          await drawCanvasUtil(&quot;backgroundSettingCustom&quot;, { &quot;fillStyle&quot;: &quot;#FFFFFF&quot;, &quot;x&quot;: 0, &quot;y&quot;: 315, &quot;width&quot;: 800, &quot;height&quot;: 802 });
          await drawCanvasUtil(&quot;drawImage&quot;, { &quot;src&quot;: imgnameSchonlogo, &quot;dx&quot;: 251, &quot;dy&quot;: 108, &quot;dWidth&quot;: 299, &quot;dHeight&quot;: 100 });
          await drawCanvasUtil(&quot;drawImage&quot;, { &quot;src&quot;: imgnameLogo, &quot;dx&quot;: 67, &quot;dy&quot;: 1234, &quot;dWidth&quot;: 300, &quot;dHeight&quot;: 150 });
          await drawCanvasUtil(&quot;Text&quot;, { &quot;font&quot;: &quot;bold 25px NotoSansB&quot;, &quot;fillStyle&quot;: &quot;#000000&quot;, &quot;textAlign&quot;: &quot;start&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: admember[&quot;corpname&quot;], &quot;x&quot;: 435, &quot;y&quot;: 1270});
          await drawCanvasUtil(&quot;copyText&quot;, { &quot;font&quot;: &quot;20px NotoSansR&quot;, &quot;fillStyle&quot;: &quot;#000000&quot;, &quot;textAlign&quot;: &quot;start&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: firstCopy[1][&quot;cpComment&quot;], &quot;x&quot;: 435, &quot;y&quot;: 1300 });
          await drawCanvasUtil(&quot;ctaBtn&quot;, { &quot;fillStyle&quot;: &quot;#85b74e&quot;, &quot;x&quot;: 433, &quot;y&quot;: 1343, &quot;width&quot;: 300, &quot;height&quot;: 50, &quot;radii&quot;: 4, &quot;font&quot;: &quot;18px NotoSansR&quot;, &quot;fontFillStyle&quot;: &quot;#FFFFFF&quot;, &quot;textAlign&quot;: &quot;center&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: &quot;바로가기&quot;, &quot;textX&quot;: 570, &quot;textY&quot;: 1370 });
          break;
        case &quot;300x300&quot;:
          await drawCanvasUtil(&quot;backgroundSetting&quot;);
          break;
        case &quot;336x280&quot;:
          await drawCanvasUtil(&quot;backgroundSettingCustom&quot;, { &quot;fillStyle&quot;: &quot;#FFFFFF&quot;, &quot;x&quot;: 0, &quot;y&quot;: 0, &quot;width&quot;: 336, &quot;height&quot;: 180 });
          await drawCanvasUtil(&quot;copyText&quot;, { &quot;font&quot;: &quot;13px NotoSansR&quot;, &quot;fillStyle&quot;: &quot;#000000&quot;, &quot;textAlign&quot;: &quot;center&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: firstCopy[1][&quot;cpComment&quot;], &quot;x&quot;: 160, &quot;y&quot;: 209 });
          await drawCanvasUtil(&quot;ctaBtn&quot;, { &quot;fillStyle&quot;: &quot;#85b74e&quot;, &quot;x&quot;: 121, &quot;y&quot;: 227, &quot;width&quot;: 95, &quot;height&quot;: 35, &quot;radii&quot;: 4, &quot;font&quot;: &quot;16px NotoSansR&quot;, &quot;fontFillStyle&quot;: &quot;#FFFFFF&quot;, &quot;textAlign&quot;: &quot;center&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: &quot;바로가기&quot;, &quot;textX&quot;: 170, &quot;textY&quot;: 245 });
          break;
        case &quot;720x1230&quot;:
          await drawCanvasUtil(&quot;backgroundSettingCustom&quot;, { &quot;fillStyle&quot;: &quot;#FFFFFF&quot;, &quot;x&quot;: 0, &quot;y&quot;: 254, &quot;width&quot;: 720, &quot;height&quot;: 722 });
          await drawCanvasUtil(&quot;drawImage&quot;, { &quot;src&quot;: imgnameSchonlogo, &quot;dx&quot;: 260, &quot;dy&quot;: 72, &quot;dWidth&quot;: 200, &quot;dHeight&quot;: 67 });
          await drawCanvasUtil(&quot;Text&quot;, { &quot;font&quot;: &quot;bold 25px NotoSansB&quot;, &quot;fillStyle&quot;: &quot;#000000&quot;, &quot;textAlign&quot;: &quot;center&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: admember[&quot;corpname&quot;], &quot;x&quot;: 348.5, &quot;y&quot;: 159 });
          await drawCanvasUtil(&quot;ctaBtn&quot;, { &quot;fillStyle&quot;: &quot;#85b74e&quot;, &quot;x&quot;: 210, &quot;y&quot;: 1078, &quot;width&quot;: 300, &quot;height&quot;: 50, &quot;radii&quot;: 4, &quot;font&quot;: &quot;18px NotoSansR&quot;, &quot;fontFillStyle&quot;: &quot;#FFFFFF&quot;, &quot;textAlign&quot;: &quot;center&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: &quot;바로가기&quot;, &quot;textX&quot;: 350, &quot;textY&quot;: 1105 });
          break;
        case &quot;320x200&quot;:
          await drawCanvasUtil(&quot;backgroundSettingCustom&quot;, { &quot;fillStyle&quot;: &quot;#FFFFFF&quot;, &quot;x&quot;: 0, &quot;y&quot;: 0, &quot;width&quot;: 200, &quot;height&quot;: 200 });
          await drawCanvasUtil(&quot;drawImage&quot;, { &quot;src&quot;: imgnameSchonlogo, &quot;dx&quot;: 210, &quot;dy&quot;: 50, &quot;dWidth&quot;: 100, &quot;dHeight&quot;: 36 });
          await drawCanvasUtil(&quot;ctaBtn&quot;, { &quot;fillStyle&quot;: &quot;#85b74e&quot;, &quot;x&quot;: 213, &quot;y&quot;: 115, &quot;width&quot;: 95, &quot;height&quot;: 35, &quot;radii&quot;: 4, &quot;font&quot;: &quot;16px NotoSansR&quot;, &quot;fontFillStyle&quot;: &quot;#FFFFFF&quot;, &quot;textAlign&quot;: &quot;center&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: &quot;바로가기&quot;, &quot;textX&quot;: 260, &quot;textY&quot;: 135 });
          break;
        case &quot;300x180&quot;:
          await drawCanvasUtil(&quot;backgroundSettingCustom&quot;, { &quot;fillStyle&quot;: &quot;#FFFFFF&quot;, &quot;x&quot;: 0, &quot;y&quot;: 0, &quot;width&quot;: 180, &quot;height&quot;: 180 });
          await drawCanvasUtil(&quot;drawImage&quot;, { &quot;src&quot;: imgnameLogo, &quot;dx&quot;: 215, &quot;dy&quot;: 43, &quot;dWidth&quot;: 50, &quot;dHeight&quot;: 50 });
          await drawCanvasUtil(&quot;copyText&quot;, { &quot;font&quot;: &quot;bold 9px NotoSansB&quot;, &quot;fillStyle&quot;: &quot;#000000&quot;, &quot;textAlign&quot;: &quot;center&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: admember[&quot;corpname&quot;], &quot;x&quot;: 240, &quot;y&quot;: 114 });
          break;
        case &quot;300x150&quot;:
          await drawCanvasUtil(&quot;backgroundSettingCustom&quot;, { &quot;fillStyle&quot;: &quot;#FFFFFF&quot;, &quot;x&quot;: 0, &quot;y&quot;: 0, &quot;width&quot;: 150, &quot;height&quot;: 150 });
          await drawCanvasUtil(&quot;ctaBtn&quot;, { &quot;fillStyle&quot;: &quot;#85b74e&quot;, &quot;x&quot;: 178, &quot;y&quot;: 77, &quot;width&quot;: 95, &quot;height&quot;: 35, &quot;radii&quot;: 4, &quot;font&quot;: &quot;16px NotoSansR&quot;, &quot;fontFillStyle&quot;: &quot;#FFFFFF&quot;, &quot;textAlign&quot;: &quot;center&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: &quot;바로가기&quot;, &quot;textX&quot;: 225, &quot;textY&quot;: 94 });
          await drawCanvasUtil(&quot;copyText&quot;, { &quot;font&quot;: &quot;9px NotoSansR&quot;, &quot;fillStyle&quot;: &quot;#000000&quot;, &quot;textAlign&quot;: &quot;start&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: firstCopy[2][&quot;cpComment&quot;], &quot;x&quot;: 160, &quot;y&quot;: 45 });
          break;
        case &quot;210x300&quot;:
          await drawCanvasUtil(&quot;backgroundSettingCustom2&quot;, { &quot;fillStyle&quot;: &quot;#FFFFFF&quot;, &quot;imgX&quot;: 0, &quot;imgY&quot;: 0, &quot;imgWidth&quot;: 210, &quot;imgHeight&quot;: 210, &quot;x&quot;: 0, &quot;y&quot;: 210, &quot;width&quot;: 210, &quot;height&quot;: 90 });
          await drawCanvasUtil(&quot;ctaBtn&quot;, { &quot;fillStyle&quot;: &quot;#85b74e&quot;, &quot;x&quot;: 58, &quot;y&quot;: 237, &quot;width&quot;: 95, &quot;height&quot;: 35, &quot;radii&quot;: 4, &quot;font&quot;: &quot;16px NotoSansR&quot;, &quot;fontFillStyle&quot;: &quot;#FFFFFF&quot;, &quot;textAlign&quot;: &quot;center&quot;, &quot;textBaseline&quot;: &quot;middle&quot;, &quot;text&quot;: &quot;바로가기&quot;, &quot;textX&quot;: 105.5, &quot;textY&quot;: 254.5 });
          break;
      }

      var resizedImage = canvas.toDataURL('image/jpeg');
      callback(null, resizedImage, newTemplate, idx);
    };
  } catch (error) {
    console.error(error);
    callback(error, null, newTemplate, idx);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Front-End</category>
      <category>canvas</category>
      <category>CanvasAPI</category>
      <category>JavaScript</category>
      <category>배너배리에이션</category>
      <category>배너베리에이션</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/13</guid>
      <comments>https://djlife.tistory.com/13#entry13comment</comments>
      <pubDate>Tue, 25 Jul 2023 10:47:26 +0900</pubDate>
    </item>
    <item>
      <title>자주 사용하는 linux 필수 명령어 모음</title>
      <link>https://djlife.tistory.com/12</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Tux.svg.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dkRPAL/btspjXd9lJV/MHlzaTG2BNdHrDD0jupNxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkRPAL/btspjXd9lJV/MHlzaTG2BNdHrDD0jupNxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkRPAL/btspjXd9lJV/MHlzaTG2BNdHrDD0jupNxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdkRPAL%2FbtspjXd9lJV%2FMHlzaTG2BNdHrDD0jupNxK%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;1200&quot; height=&quot;1422&quot; data-filename=&quot;Tux.svg.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1422&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 서버 어플리케이션 혹은 컨테이너 환경이 Linux 기반의 OS 에서 구동하기 때문에.. centos,ubuntu...&lt;br /&gt;백엔드 개발자 혹은 서버 어플리케이션을 개발 및 운영해야하는 개발자분들한테 Linux&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;이쯤되면 외워질 법한데 자꾸 까먹고 검색하게 되어 임시로 정리해놓은 글..&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt; &amp;nbsp;pwd &lt;br /&gt;print&amp;nbsp;work&amp;nbsp;directory의&amp;nbsp;약자로&amp;nbsp;작업&amp;nbsp;중인&amp;nbsp;디렉터리를&amp;nbsp;보여줍니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;ls &lt;br /&gt;list&amp;nbsp;segments의&amp;nbsp;약자로&amp;nbsp;현재&amp;nbsp;디렉터리의&amp;nbsp;파일과&amp;nbsp;디렉터리를&amp;nbsp;보여줍니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;cd &lt;br /&gt;change&amp;nbsp;directory의&amp;nbsp;약자로&amp;nbsp;말그대로&amp;nbsp;디렉터리&amp;nbsp;이동&amp;nbsp;시&amp;nbsp;사용하는&amp;nbsp;명령입니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;mkdir &lt;br /&gt;make&amp;nbsp;directory의&amp;nbsp;약자로&amp;nbsp;디렉터리를&amp;nbsp;만들&amp;nbsp;때&amp;nbsp;사용합니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;cp &lt;br /&gt;copy의&amp;nbsp;약자입니다.&amp;nbsp;파일&amp;nbsp;또는&amp;nbsp;디렉터리를&amp;nbsp;복사할&amp;nbsp;때&amp;nbsp;사용합니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;mv &lt;br /&gt;move의&amp;nbsp;약자입니다.&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;rm &lt;br /&gt;remove의&amp;nbsp;약자입니다.&amp;nbsp;파일&amp;nbsp;또는&amp;nbsp;디렉터리를&amp;nbsp;삭제할&amp;nbsp;때&amp;nbsp;사용합니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;cat &lt;br /&gt;catenate&amp;nbsp;(잇다&amp;nbsp;연결하다)의&amp;nbsp;약자입니다.&amp;nbsp;파일의&amp;nbsp;내용을&amp;nbsp;확인할&amp;nbsp;때&amp;nbsp;사용합니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;touch &lt;br /&gt;touch는&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;echo &lt;br /&gt;echo는&amp;nbsp;어떤&amp;nbsp;문자열을&amp;nbsp;화면에&amp;nbsp;보여줄&amp;nbsp;때&amp;nbsp;사용합니다.&amp;nbsp;echo와&amp;nbsp;리다이렉션을&amp;nbsp;사용해&amp;nbsp;파일을&amp;nbsp;생성,&amp;nbsp;추가하는&amp;nbsp;작업을&amp;nbsp;많이&amp;nbsp;합니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;ip&amp;nbsp;addr&amp;nbsp;/&amp;nbsp;ifconfig &lt;br /&gt;접속한&amp;nbsp;리눅스의&amp;nbsp;IP&amp;nbsp;정보를&amp;nbsp;알아낼&amp;nbsp;때&amp;nbsp;사용합니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;ss &lt;br /&gt;socket&amp;nbsp;statistics의&amp;nbsp;약자입니다.&amp;nbsp;네트워크&amp;nbsp;상태를&amp;nbsp;확인하는&amp;nbsp;데&amp;nbsp;사용합니다.&amp;nbsp; &lt;br /&gt;&lt;br /&gt; &amp;nbsp;nc &lt;br /&gt;netcat의&amp;nbsp;약자입니다.&amp;nbsp;포트를&amp;nbsp;오픈하거나&amp;nbsp;오픈되었는지&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있습니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;which,&amp;nbsp;whereis,&amp;nbsp;locate &lt;br /&gt;특정&amp;nbsp;명령어의&amp;nbsp;위치를&amp;nbsp;찾아줍니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;tail &lt;br /&gt;파일의&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;find &lt;br /&gt;find는&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;ps &lt;br /&gt;현재&amp;nbsp;실행&amp;nbsp;중인&amp;nbsp;프로세스&amp;nbsp;목록과&amp;nbsp;상태를&amp;nbsp;보여줍니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;grep &lt;br /&gt;grep은&amp;nbsp;입력에서&amp;nbsp;패턴에&amp;nbsp;매칭되는&amp;nbsp;내용을&amp;nbsp;찾는&amp;nbsp;명령어입니다.&amp;nbsp; &lt;br /&gt;&lt;br /&gt; &amp;nbsp;kill &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;SIGKILL,&amp;nbsp;SIGSTOP은&amp;nbsp;강제&amp;nbsp;종료이며&amp;nbsp;나머지는&amp;nbsp;정상적으로&amp;nbsp;종료시킵니다.&amp;nbsp; &lt;br /&gt;&lt;br /&gt; &amp;nbsp;alias &lt;br /&gt;자주&amp;nbsp;사용하는&amp;nbsp;명령어가&amp;nbsp;길&amp;nbsp;경우&amp;nbsp;alias&amp;nbsp;를&amp;nbsp;사용하면&amp;nbsp;줄여서&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있습니다. &lt;br /&gt;&lt;br /&gt; &amp;nbsp;vi&amp;nbsp;/&amp;nbsp;vim &lt;br /&gt;vi&amp;nbsp;혹은&amp;nbsp;vim은&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://yozm.wishket.com/magazine/detail/2103/&quot;&gt;https://yozm.wishket.com/magazine/detail/2103/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690100191958&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;백엔드 개발자라면 알아야 할 리눅스 필수 명령어 21개 | 요즘IT&quot; data-og-description=&quot;백엔드 개발자가 아니면 리눅스를 사용할 일이 거의 없습니다. 그러므로 백엔드 입문자인 여러분께 리눅스 명령어는 낯설기 마련입니다. 명령어는 방대하기 때문에 처음부터 모든 명령어를 다 &quot; data-og-host=&quot;yozm.wishket.com&quot; data-og-source-url=&quot;https://yozm.wishket.com/magazine/detail/2103/&quot; data-og-url=&quot;https://yozm.wishket.com/magazine/detail/2103/yozm.wishket.com/magazine/detail/2103/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bbDfmx/hyTo1c8yLV/sjcE9dVHRcKI0RbwZsE331/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/cBpcFU/hyTpfWMpDw/dHijlVampzNuhKkfV3VHPK/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot;&gt;&lt;a href=&quot;https://yozm.wishket.com/magazine/detail/2103/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://yozm.wishket.com/magazine/detail/2103/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bbDfmx/hyTo1c8yLV/sjcE9dVHRcKI0RbwZsE331/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/cBpcFU/hyTpfWMpDw/dHijlVampzNuhKkfV3VHPK/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;백엔드 개발자라면 알아야 할 리눅스 필수 명령어 21개 | 요즘IT&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;백엔드 개발자가 아니면 리눅스를 사용할 일이 거의 없습니다. 그러므로 백엔드 입문자인 여러분께 리눅스 명령어는 낯설기 마련입니다. 명령어는 방대하기 때문에 처음부터 모든 명령어를 다&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;yozm.wishket.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/DevOps</category>
      <category>command</category>
      <category>Linux</category>
      <category>리눅스 명령어</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/12</guid>
      <comments>https://djlife.tistory.com/12#entry12comment</comments>
      <pubDate>Sun, 23 Jul 2023 17:21:13 +0900</pubDate>
    </item>
    <item>
      <title>github &amp;amp; Jenkins CI/CD 자동 빌드 배포 환경 구성하기 - 1</title>
      <link>https://djlife.tistory.com/11</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;젠킨스 CI / CD 환경을 여러번 구성하였지만&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;
&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 나는 NHN클라우드 - 인스턴스 - 리눅스(centos 7) 환경에서 작업하고 있다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;898&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q0SXR/btsjXwFfS3v/pkIREL9Y60gd0lEJVjmhs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q0SXR/btsjXwFfS3v/pkIREL9Y60gd0lEJVjmhs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q0SXR/btsjXwFfS3v/pkIREL9Y60gd0lEJVjmhs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ0SXR%2FbtsjXwFfS3v%2FpkIREL9Y60gd0lEJVjmhs0%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;1674&quot; height=&quot;898&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;898&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1311&quot; data-origin-height=&quot;833&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bybCQ5/btsjPpt7OCj/f6ZtPVhjYshE2KvMHe0GXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bybCQ5/btsjPpt7OCj/f6ZtPVhjYshE2KvMHe0GXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bybCQ5/btsjPpt7OCj/f6ZtPVhjYshE2KvMHe0GXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbybCQ5%2FbtsjPpt7OCj%2Ff6ZtPVhjYshE2KvMHe0GXK%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;1311&quot; height=&quot;833&quot; data-origin-width=&quot;1311&quot; data-origin-height=&quot;833&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종종 이렇게 git 저장소와 연결 설정 할 경우&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;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;Failed&amp;nbsp;to&amp;nbsp;connect&amp;nbsp;to&amp;nbsp;repository&amp;nbsp;:&amp;nbsp;Error&amp;nbsp;performing&amp;nbsp;command:&amp;nbsp;git.exe&amp;nbsp;ls-remote&amp;nbsp;-h&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/DongJu-Na/Nadry&quot;&gt;https://github.com/DongJu-Na/Nadry&lt;/a&gt;&lt;a style=&quot;color: #ee2323;&quot; href=&quot;https://github.com/szabbas/Sample-programs.git&quot;&gt;.git&lt;/a&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;&amp;nbsp;HEAD&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #f7f7f8; color: #374151; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&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;방화벽 또는 프록시 설정으로 인해 GitHub 저장소에 접근할 수 없는 경우, 네트워크 구성을 확인하고 접근 제한 사항을 조정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;잘못된 저장소 URL:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GitHub 저장소의 URL이 올바르게 지정되었는지 확인&lt;/li&gt;
&lt;li&gt;오타가 있는지 다시 한 번 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;GitHub API 토큰이나 사용자 인증 정보를 제공하여 저장소에 액세스할 수 있도록 젠킨스 구성을 업데이트&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Git 설치 문제:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;젠킨스 서버에 Git이 정상적으로 설치되었는지 확인&lt;/li&gt;
&lt;li&gt;실행할 수 있는 권한이 있는지 확인&lt;/li&gt;
&lt;li&gt;필요에 따라 Git을 업데이트하거나 권한을 조정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분 3,4 에 해당하니 확인하고 설정을 수정하면 해결된다  &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;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;나는 한 저장소에 프론트엔드와 백엔드를 묶어서 구성해놓았기에&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;젠킨스 스크립트(&lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;Execute shell&lt;/span&gt;)를 이용하여 웹훅 -&amp;gt; 빌드 - &amp;gt; 배포 환경을 구성하였다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1686732175619&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 변경된 파일 목록 확인
#!/bin/bash
changed_files=$(git diff --name-only HEAD^ HEAD)
echo changed_files
# 프론트엔드 소스 변경 시
if [[ $changed_files == *&quot;client&quot;* ]]; then
    # 프론트엔드 빌드 및 배포 작업
    cd /var/lib/jenkins/workspace/Nadry/client/
    # 프론트엔드 빌드 스크립트 실행 예시
    npm install
    npm run build
    # 프론트엔드 배포 스크립트 실행 예시
    rsync -avz ./build/ user@example.com:/var/www/frontend

# 백엔드 소스 변경 시
else
	java -version
    # 백엔드 빌드 및 배포 작업
    # 예시: 서버 재시작 등의 작업을 포함할 수 있습니다.
    cd /var/lib/jenkins/workspace/Nadry/
    chmod +x gradlew
    ./gradlew clean build
    
    # 백엔드 Jar 파일 실행
    jar_path=&quot;/var/lib/jenkins/workspace/Nadry/build/libs/ndj-0.0.1-SNAPSHOT.jar&quot;
    process_id=$(lsof -ti :8082 || true)  # 8082 포트에 실행 중인 프로세스 ID 조회

    # 실행 중인 프로세스 종료
    if [[ ! -z $process_id ]]; then
        echo &quot;Terminating existing process with PID: $process_id&quot;
        kill -9 $process_id
    else
        echo &quot;No process is running on port 8082.&quot;
    fi
    
    # Jar 파일 실행 (nohup으로 백그라운드 실행)
    sudo nohup java -jar $jar_path &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 &amp;amp;
    
    echo &quot;Backend application started.&quot;
fi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만일 &lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;Execute shell에서 lsof와 nohup이 동작하지 않는다면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;젠킨스 서버 사용자(jenkins)에 권한이 있는지 확인&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 style=&quot;color: #14141f;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;없다면 sudo visudo 를 이용하여 &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #14141f;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;jenkins ALL=(ALL) NOPASSWD: /usr/sbin/lsof&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jenkins&amp;nbsp;ALL=(ALL)&amp;nbsp;NOPASSWD:&amp;nbsp;/usr/bin/nohup&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;&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;완성된 CI &amp;amp; CD 아키텍처&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;architecture.drawio.png&quot; data-origin-width=&quot;1993&quot; data-origin-height=&quot;1252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6j6p1/btsjYwlGxtd/kgpXNgX40s9hSf0vLFh5w0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6j6p1/btsjYwlGxtd/kgpXNgX40s9hSf0vLFh5w0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6j6p1/btsjYwlGxtd/kgpXNgX40s9hSf0vLFh5w0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6j6p1%2FbtsjYwlGxtd%2FkgpXNgX40s9hSf0vLFh5w0%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;1993&quot; height=&quot;1252&quot; data-filename=&quot;architecture.drawio.png&quot; data-origin-width=&quot;1993&quot; data-origin-height=&quot;1252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2편에서는 무중단 배포로 작성하는게 목표..&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;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/35863528/failed-to-connect-to-repository-error-performing-command-git-exe-ls-remote-h&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/35863528/failed-to-connect-to-repository-error-performing-command-git-exe-ls-remote-h&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1686671520563&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Failed to connect to repository : Error performing command: git.exe ls-remote -h https://github.com/szabbas/Sample-programs.git &quot; data-og-description=&quot;I am new to programming and trying to work with GIT repository and while configuring with the JENKINS is facing the error. I know it's a silly question but on a beginner point of view I am stuck an...&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/35863528/failed-to-connect-to-repository-error-performing-command-git-exe-ls-remote-h&quot; data-og-url=&quot;https://stackoverflow.com/questions/35863528/failed-to-connect-to-repository-error-performing-command-git-exe-ls-remote-h&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gxAwQ/hyS0cdVA2e/9ud6Kegkmk8t1bDI1UMaI1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/dnHRjf/hyS0a8f7LN/gZQGP4YOcjOhnKCeGQW9yK/img.png?width=1366&amp;amp;height=768&amp;amp;face=0_0_1366_768,https://scrap.kakaocdn.net/dn/Ma6T6/hySYNfL3ss/bc50jWjjC7KCKaquyhYHEk/img.png?width=1366&amp;amp;height=768&amp;amp;face=0_0_1366_768&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/35863528/failed-to-connect-to-repository-error-performing-command-git-exe-ls-remote-h&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/35863528/failed-to-connect-to-repository-error-performing-command-git-exe-ls-remote-h&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gxAwQ/hyS0cdVA2e/9ud6Kegkmk8t1bDI1UMaI1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/dnHRjf/hyS0a8f7LN/gZQGP4YOcjOhnKCeGQW9yK/img.png?width=1366&amp;amp;height=768&amp;amp;face=0_0_1366_768,https://scrap.kakaocdn.net/dn/Ma6T6/hySYNfL3ss/bc50jWjjC7KCKaquyhYHEk/img.png?width=1366&amp;amp;height=768&amp;amp;face=0_0_1366_768');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Failed to connect to repository : Error performing command: git.exe ls-remote -h https://github.com/szabbas/Sample-programs.git&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I am new to programming and trying to work with GIT repository and while configuring with the JENKINS is facing the error. I know it's a silly question but on a beginner point of view I am stuck an...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/DevOps</category>
      <category>cd</category>
      <category>CI</category>
      <category>CI&amp;amp;CD</category>
      <category>github</category>
      <category>Jenkins</category>
      <category>NHN</category>
      <category>nhn클라우드</category>
      <category>WebHook</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/11</guid>
      <comments>https://djlife.tistory.com/11#entry11comment</comments>
      <pubDate>Wed, 14 Jun 2023 17:46:04 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Cloud] 스프링 클라우드 란 무엇인가요?</title>
      <link>https://djlife.tistory.com/10</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;195-1955230_cloud-gateway-spring-cloud-contract-logo.png&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5mruS/btscQmYpESs/LKrpmoEuFW9lI4yEebKn91/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5mruS/btscQmYpESs/LKrpmoEuFW9lI4yEebKn91/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5mruS/btscQmYpESs/LKrpmoEuFW9lI4yEebKn91/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5mruS%2FbtscQmYpESs%2FLKrpmoEuFW9lI4yEebKn91%2Fimg.jpg&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;300&quot; height=&quot;198&quot; data-filename=&quot;195-1955230_cloud-gateway-spring-cloud-contract-logo.png&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스프링&amp;nbsp;클라우드(Spring&amp;nbsp;Cloud)&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; &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;사용됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cloud-3.png&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;415&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AqRZq/btscP9E1Nwr/ijaTUIowQEtx3KRaNW3fZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AqRZq/btscP9E1Nwr/ijaTUIowQEtx3KRaNW3fZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AqRZq/btscP9E1Nwr/ijaTUIowQEtx3KRaNW3fZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAqRZq%2FbtscP9E1Nwr%2FijaTUIowQEtx3KRaNW3fZk%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;745&quot; height=&quot;415&quot; data-filename=&quot;cloud-3.png&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;415&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;lt;스프링 클라우드 아키텍처&amp;gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&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;style6&quot; /&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;br /&gt;스프링&amp;nbsp;클라우드는&amp;nbsp;다음과&amp;nbsp;같은&amp;nbsp;기능들을&amp;nbsp;제공합니다. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;서비스&amp;nbsp;디스커버리(Service&amp;nbsp;Discovery)&lt;/b&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;Netflix&amp;nbsp;OSS의&amp;nbsp;Eureka,&amp;nbsp;Apache&amp;nbsp;ZooKeeper,&amp;nbsp;Consul&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;서비스&amp;nbsp;디스커버리&amp;nbsp;툴과&amp;nbsp;통합되어&amp;nbsp;있습니다. &lt;br /&gt;&lt;b&gt;API 게이트웨이(API Gateway)&lt;/b&gt;: API 게이트웨이는 여러 개의 마이크로서비스에서 제공하는 API를 단일 진입점으로 노출시켜 주는 역할을 합니다. 스프링 클라우드는 Netflix OSS의 Zuul, Spring Cloud Gateway 등 다양한 API 게이트웨이를 제공합니다. &lt;br /&gt;&lt;b&gt;분산&amp;nbsp;설정(Distributed&amp;nbsp;Configuration)&lt;/b&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;설정&amp;nbsp;관리를&amp;nbsp;위한&amp;nbsp;Spring&amp;nbsp;Cloud&amp;nbsp;Config를&amp;nbsp;제공합니다. &lt;br /&gt;&lt;b&gt;분산&amp;nbsp;추적(Distributed&amp;nbsp;Tracing):&lt;/b&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;Spring&amp;nbsp;Cloud&amp;nbsp;Sleuth와&amp;nbsp;Zipkin을&amp;nbsp;제공합니다. &lt;br /&gt;&lt;b&gt;로드&amp;nbsp;밸런싱(Load&amp;nbsp;Balancing)&lt;/b&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;Ribbon을&amp;nbsp;사용한&amp;nbsp;로드&amp;nbsp;밸런싱을&amp;nbsp;제공합니다. &lt;br /&gt;&lt;b&gt;회로&amp;nbsp;차단기(Circuit&amp;nbsp;Breaker)&lt;/b&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;스프링&amp;nbsp;클라우드는&amp;nbsp;Netflix&amp;nbsp;OSS의&amp;nbsp;Hystrix를&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;Spring&amp;nbsp;Cloud는&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;Spring&amp;nbsp;Cloud는&amp;nbsp;여러&amp;nbsp;마이크로서비스를&amp;nbsp;각각의&amp;nbsp;독립적인&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;Spring&amp;nbsp;Cloud는&amp;nbsp;Netflix&amp;nbsp;OSS&amp;nbsp;프로젝트에서&amp;nbsp;시작한&amp;nbsp;것으로,&amp;nbsp;Eureka,&amp;nbsp;Ribbon,&amp;nbsp;Hystrix,&amp;nbsp;Zuul&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;서비스를&amp;nbsp;포함하고&amp;nbsp;있습니다.&amp;nbsp; &lt;br /&gt;이러한&amp;nbsp;Spring&amp;nbsp;Cloud의&amp;nbsp;기능들은&amp;nbsp;분산&amp;nbsp;시스템에서&amp;nbsp;필요한&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;Spring&amp;nbsp;Cloud는&amp;nbsp;Spring&amp;nbsp;Boot와&amp;nbsp;밀접하게&amp;nbsp;연관되어&amp;nbsp;있어서,&amp;nbsp;Spring&amp;nbsp;Boot를&amp;nbsp;기반으로&amp;nbsp;하는&amp;nbsp;애플리케이션에서&amp;nbsp;Spring&amp;nbsp;Cloud&amp;nbsp;기능을&amp;nbsp;쉽게&amp;nbsp;활용할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;Spring&amp;nbsp;Cloud는&amp;nbsp;Netflix&amp;nbsp;OSS와&amp;nbsp;함께&amp;nbsp;Spring&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;&lt;br /&gt;&lt;b&gt;Spring&amp;nbsp;Cloud&amp;nbsp;Config&lt;/b&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;이를&amp;nbsp;통해,&amp;nbsp;애플리케이션의&amp;nbsp;설정&amp;nbsp;정보를&amp;nbsp;손쉽게&amp;nbsp;수정하고&amp;nbsp;배포할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp; &lt;br /&gt;Config&amp;nbsp;서버는&amp;nbsp;Git,&amp;nbsp;Subversion,&amp;nbsp;Vault&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;&lt;br /&gt;&lt;b&gt;Spring&amp;nbsp;Cloud&amp;nbsp;Gateway&lt;/b&gt;는&amp;nbsp;API&amp;nbsp;게이트웨이&amp;nbsp;역할을&amp;nbsp;합니다.&amp;nbsp; &lt;br /&gt;API&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; &lt;br /&gt;Gateway를&amp;nbsp;사용하면,&amp;nbsp;여러&amp;nbsp;개의&amp;nbsp;서비스를&amp;nbsp;하나의&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;Gateway는&amp;nbsp;이를&amp;nbsp;위해&amp;nbsp;다양한&amp;nbsp;라우팅&amp;nbsp;방식을&amp;nbsp;제공합니다.&amp;nbsp; &lt;br /&gt;예를&amp;nbsp;들어,&amp;nbsp;URI,&amp;nbsp;Hostname,&amp;nbsp;Path,&amp;nbsp;Query&amp;nbsp;parameter&amp;nbsp;등을&amp;nbsp;이용한&amp;nbsp;라우팅&amp;nbsp;방식이&amp;nbsp;있습니다. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Spring&amp;nbsp;Cloud&amp;nbsp;Discovery&lt;/b&gt;는&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;검색하고&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;기능을&amp;nbsp;의미합니다.&amp;nbsp; &lt;br /&gt;Discovery를&amp;nbsp;사용하면,&amp;nbsp;서비스&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;Discovery&amp;nbsp;클라이언트는&amp;nbsp;Eureka,&amp;nbsp;Consul,&amp;nbsp;Zookeeper&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;백엔드를&amp;nbsp;지원하며,&amp;nbsp;서비스&amp;nbsp;인스턴스의&amp;nbsp;상태를&amp;nbsp;추적하고,&amp;nbsp;이를&amp;nbsp;Config&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; &lt;br /&gt;Config&amp;nbsp;서버에서&amp;nbsp;구성&amp;nbsp;정보를&amp;nbsp;가져와서&amp;nbsp;Gateway를&amp;nbsp;구성하고,&amp;nbsp;Discovery를&amp;nbsp;사용하여&amp;nbsp;서비스&amp;nbsp;인스턴스를&amp;nbsp;검색하여&amp;nbsp;Gateway에&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;높은&amp;nbsp;가용성과&amp;nbsp;확장성을&amp;nbsp;보장할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp; &lt;br /&gt;예를&amp;nbsp;들어,&amp;nbsp;Config&amp;nbsp;서버에서&amp;nbsp;포트&amp;nbsp;정보를&amp;nbsp;가져와서&amp;nbsp;Gateway의&amp;nbsp;라우팅&amp;nbsp;규칙을&amp;nbsp;동적으로&amp;nbsp;업데이트하거나,&amp;nbsp; &lt;br /&gt;Discovery를&amp;nbsp;사용하여&amp;nbsp;서비스&amp;nbsp;인스턴스의&amp;nbsp;상태를&amp;nbsp;추적하여&amp;nbsp;Gateway의&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;관련 Doc.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://spring.io/projects/spring-cloud&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://spring.io/projects/spring-cloud&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1682562379708&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Spring | Home&quot; data-og-description=&quot;Cloud Your code, any cloud&amp;mdash;we&amp;rsquo;ve got you covered. Connect and scale your services, whatever your platform.&quot; data-og-host=&quot;spring.io&quot; data-og-source-url=&quot;https://spring.io/projects/spring-cloud&quot; data-og-url=&quot;https://spring.io&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bhWWyo/hySpycefvw/eacXz4CykSmjyPASwNSrF1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://spring.io/projects/spring-cloud&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://spring.io/projects/spring-cloud&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bhWWyo/hySpycefvw/eacXz4CykSmjyPASwNSrF1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Spring | Home&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Cloud Your code, any cloud&amp;mdash;we&amp;rsquo;ve got you covered. Connect and scale your services, whatever your platform.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/spring-cloud&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/spring-cloud&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1682562389532&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;profile&quot; data-og-title=&quot;Spring Cloud&quot; data-og-description=&quot;Tools for building common patterns in distributed systems with Spring - Spring Cloud&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/spring-cloud&quot; data-og-url=&quot;https://github.com/spring-cloud&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rX05D/hySpGVBbMj/NmmU2XRIxIVmZFas01KNLk/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200&quot;&gt;&lt;a href=&quot;https://github.com/spring-cloud&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/spring-cloud&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rX05D/hySpGVBbMj/NmmU2XRIxIVmZFas01KNLk/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Spring Cloud&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Tools for building common patterns in distributed systems with Spring - Spring Cloud&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2023.11.23 추가&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;전&amp;nbsp;GitHub&amp;nbsp;CTO,&amp;nbsp;&quot;지난&amp;nbsp;10년간&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;&lt;a href=&quot;https://news.hada.io/topic?id=7839&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://news.hada.io/topic?id=7839&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1700708237689&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;전 GitHub CTO, &amp;quot;지난 10년간 가장 큰 아키텍처 실수는 풀 마이크로서비스로 전환 | GeekNews&quot; data-og-description=&quot;&amp;quot;Monolith &amp;gt; apps &amp;gt; services &amp;gt; microservices&amp;quot;첫째, 이건 규칙은 아니고 내 생각이 그렇다는 것. 대규모 분산 시스템을 구축해 본 사람은 실제로 그대로 작동하지 않으며, 적응해야 한다는 것을 알고 있음둘&quot; data-og-host=&quot;news.hada.io&quot; data-og-source-url=&quot;https://news.hada.io/topic?id=7839&quot; data-og-url=&quot;https://news.hada.io/topic?id=7839&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/5E2C0/hyUB9tMLVg/hyzkbIvJmbWmihLLYwfKd1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://news.hada.io/topic?id=7839&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://news.hada.io/topic?id=7839&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/5E2C0/hyUB9tMLVg/hyzkbIvJmbWmihLLYwfKd1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;전 GitHub CTO, &quot;지난 10년간 가장 큰 아키텍처 실수는 풀 마이크로서비스로 전환 | GeekNews&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&quot;Monolith &amp;gt; apps &amp;gt; services &amp;gt; microservices&quot;첫째, 이건 규칙은 아니고 내 생각이 그렇다는 것. 대규모 분산 시스템을 구축해 본 사람은 실제로 그대로 작동하지 않으며, 적응해야 한다는 것을 알고 있음둘&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;news.hada.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;&lt;a href=&quot;https://github.com/DongJu-Na/spring-cloud-sample&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/DongJu-Na/spring-cloud-sample&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1702216719501&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - DongJu-Na/spring-cloud-sample: Spring MSA architecture Sample Project&quot; data-og-description=&quot;Spring MSA architecture Sample Project. Contribute to DongJu-Na/spring-cloud-sample development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/DongJu-Na/spring-cloud-sample&quot; data-og-url=&quot;https://github.com/DongJu-Na/spring-cloud-sample&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fv62H/hyUIGe8HIV/Z1iP4urMkx6J9OOuTnkrF1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na/spring-cloud-sample&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/DongJu-Na/spring-cloud-sample&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fv62H/hyUIGe8HIV/Z1iP4urMkx6J9OOuTnkrF1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - DongJu-Na/spring-cloud-sample: Spring MSA architecture Sample Project&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Spring MSA architecture Sample Project. Contribute to DongJu-Na/spring-cloud-sample development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>apiserver</category>
      <category>configserver</category>
      <category>spring</category>
      <category>spring cloud</category>
      <category>Spring Cloud Discovery</category>
      <category>스프링클라우드</category>
      <category>클라우드</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/10</guid>
      <comments>https://djlife.tistory.com/10#entry10comment</comments>
      <pubDate>Thu, 27 Apr 2023 11:55:03 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Boot] H2  in memory DB 사용 시  Database &amp;quot;C:/Users/사용자/test&amp;quot; not found, either pre-create it or allow remote database creation (not recommended in secure environments) 오류 발생 / 해결 방법</title>
      <link>https://djlife.tistory.com/9</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Webflux 공부 중&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Database를 사용해야 되는 상황이 생겨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 구성하긴 번거롭고.. 예전 기억을 살려 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;간단하게&amp;nbsp;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;H2 Database 사용하려고 하는데&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvYiY8/btr7HfDNEJ0/eBqXZ30zWb9Ch5zc2iOpt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvYiY8/btr7HfDNEJ0/eBqXZ30zWb9Ch5zc2iOpt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvYiY8/btr7HfDNEJ0/eBqXZ30zWb9Ch5zc2iOpt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvYiY8%2Fbtr7HfDNEJ0%2FeBqXZ30zWb9Ch5zc2iOpt1%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;1006&quot; height=&quot;463&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오류 상세 내용을 확인 하면&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6dwF2/btr7UKBSJz2/q83SMxKUUK5mt8scNQ9jpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6dwF2/btr7UKBSJz2/q83SMxKUUK5mt8scNQ9jpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6dwF2/btr7UKBSJz2/q83SMxKUUK5mt8scNQ9jpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6dwF2%2Fbtr7UKBSJz2%2Fq83SMxKUUK5mt8scNQ9jpk%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;1142&quot; height=&quot;328&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;328&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 사용 했을 때는 Database를 자동으로 생성 했던 걸로 기억하는데&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;문제해결&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;gt; database를 사전 생성 해서 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Database를 생성하는 방법은 아래 링크를 참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt; 문서 볼 시간도 아깝다.. 당장 해결만 하고자 한다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;해당 경로에 메모장을 만든 후 파일명을 test.mv.db 로 수정 후 저장하면 해결된다. (test는 커넥션팩토리에서 설정한 스키마명)&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;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://h2database.com/html/tutorial.html#creating_new_databases&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://h2database.com/html/tutorial.html#creating_new_databases&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1680573038046&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Tutorial&quot; data-og-description=&quot;&amp;nbsp; Tutorial Starting and Using the H2 Console Special H2 Console Syntax Settings of the H2 Console Connecting to a Database using JDBC Creating New Databases Using the Server Using Hibernate Using TopLink and Glassfish Using EclipseLink Using Apache Active&quot; data-og-host=&quot;h2database.com&quot; data-og-source-url=&quot;https://h2database.com/html/tutorial.html#creating_new_databases&quot; data-og-url=&quot;https://h2database.com/html/tutorial.html#creating_new_databases&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://h2database.com/html/tutorial.html#creating_new_databases&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://h2database.com/html/tutorial.html#creating_new_databases&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Tutorial&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Tutorial Starting and Using the H2 Console Special H2 Console Syntax Settings of the H2 Console Connecting to a Database using JDBC Creating New Databases Using the Server Using Hibernate Using TopLink and Glassfish Using EclipseLink Using Apache Active&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;h2database.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;h1 style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;database can't auto create in 1.4.200 if not schema and data&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;관련 Issue&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/h2database/h2database/issues/2900&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/h2database/h2database/issues/2900&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1680573139589&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;database can't auto create in 1.4.200 if not schema and data &amp;middot; Issue #2900 &amp;middot; h2database/h2database&quot; data-og-description=&quot;I have a SpringBoot maven project. JDK8, SpringBoot 1.4.4.RELEASE My pom.xml is &amp;lt;dependency&amp;gt; &amp;lt;groupId&amp;gt;com.h2database&amp;lt;/groupId&amp;gt; &amp;lt;artifactId&amp;gt;h2&amp;lt;/artifactId&amp;gt; &amp;lt;version&amp;gt;1.4.200&amp;lt;/version&amp;gt; &amp;lt;/dependency&amp;gt; &amp;lt;...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/h2database/h2database/issues/2900&quot; data-og-url=&quot;https://github.com/h2database/h2database/issues/2900&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bvPHPl/hyR9Ofab37/AR5OfE2bJc4u6hwjyM7Yk1/img.png?width=1200&amp;amp;height=600&amp;amp;face=976_91_1054_175&quot;&gt;&lt;a href=&quot;https://github.com/h2database/h2database/issues/2900&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/h2database/h2database/issues/2900&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bvPHPl/hyR9Ofab37/AR5OfE2bJc4u6hwjyM7Yk1/img.png?width=1200&amp;amp;height=600&amp;amp;face=976_91_1054_175');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;database can't auto create in 1.4.200 if not schema and data &amp;middot; Issue #2900 &amp;middot; h2database/h2database&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I have a SpringBoot maven project. JDK8, SpringBoot 1.4.4.RELEASE My pom.xml is &amp;lt;dependency&amp;gt; &amp;lt;groupId&amp;gt;com.h2database&amp;lt;/groupId&amp;gt; &amp;lt;artifactId&amp;gt;h2&amp;lt;/artifactId&amp;gt; &amp;lt;version&amp;gt;1.4.200&amp;lt;/version&amp;gt; &amp;lt;/dependency&amp;gt; &amp;lt;...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;H2 Database Github&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/h2database/h2database&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/h2database/h2database&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1680572697388&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - h2database/h2database: H2 is an embeddable RDBMS written in Java.&quot; data-og-description=&quot;H2 is an embeddable RDBMS written in Java. Contribute to h2database/h2database development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/h2database/h2database&quot; data-og-url=&quot;https://github.com/h2database/h2database&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bP4ZAS/hyR9KX5Hh9/KTtCdDYvsEPFF2w6DWrRq1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/h2database/h2database&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/h2database/h2database&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bP4ZAS/hyR9KX5Hh9/KTtCdDYvsEPFF2w6DWrRq1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - h2database/h2database: H2 is an embeddable RDBMS written in Java.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;H2 is an embeddable RDBMS written in Java. Contribute to h2database/h2database development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Webflux 환경일 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/r2dbc/r2dbc-h2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/r2dbc/r2dbc-h2&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1680575479724&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - r2dbc/r2dbc-h2: R2DBC H2 Implementation&quot; data-og-description=&quot;R2DBC H2 Implementation. Contribute to r2dbc/r2dbc-h2 development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/r2dbc/r2dbc-h2&quot; data-og-url=&quot;https://github.com/r2dbc/r2dbc-h2&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bjBJma/hyR9HAk546/DtZxWfRQbm2SKBXrEsm2Bk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/r2dbc/r2dbc-h2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/r2dbc/r2dbc-h2&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bjBJma/hyR9HAk546/DtZxWfRQbm2SKBXrEsm2Bk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - r2dbc/r2dbc-h2: R2DBC H2 Implementation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;R2DBC H2 Implementation. Contribute to r2dbc/r2dbc-h2 development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>github</category>
      <category>H2</category>
      <category>InMemoryDB</category>
      <category>spring boot</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/9</guid>
      <comments>https://djlife.tistory.com/9#entry9comment</comments>
      <pubDate>Tue, 4 Apr 2023 10:53:25 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Web Mvc Vs Web Flux</title>
      <link>https://djlife.tistory.com/8</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;웹 개발 할 때 Webflux ? WebMvc? 어느 것을 선택해야 하는거야!!!  &lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f3136.png&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;215&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bapLeu/btr1ud52T1y/MUvTjrHkEv1SZrh2fT64f1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bapLeu/btr1ud52T1y/MUvTjrHkEv1SZrh2fT64f1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bapLeu/btr1ud52T1y/MUvTjrHkEv1SZrh2fT64f1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbapLeu%2Fbtr1ud52T1y%2FMUvTjrHkEv1SZrh2fT64f1%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;705&quot; height=&quot;215&quot; data-filename=&quot;68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f3136.png&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;215&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebMvc와 Webflux 개념을 알기 전에!!!&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;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동기&lt;/b&gt;와 &lt;b&gt;비동기&lt;/b&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;동기&lt;/b&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;
&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;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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;905&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LzJ4I/btr1IK9u9YE/5JRJr7LCA5afEXK3GrYCXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LzJ4I/btr1IK9u9YE/5JRJr7LCA5afEXK3GrYCXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LzJ4I/btr1IK9u9YE/5JRJr7LCA5afEXK3GrYCXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLzJ4I%2Fbtr1IK9u9YE%2F5JRJr7LCA5afEXK3GrYCXk%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;905&quot; height=&quot;674&quot; data-origin-width=&quot;905&quot; data-origin-height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;WebFlux &lt;/b&gt;와 &lt;b&gt;Web MVC&lt;/b&gt;는 스프링 프레임워크에서 웹 애플리케이션을 개발할 때 사용할 수 있는 옵션이야. 근데 둘은 서로 다른 방식으로 작동하니까 선택할 때는 몇 가지 요소를 고려해야해.  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Web MVC는 기존에 있던 Spring MVC를 기반으로 만들어졌고, Servlet 스펙을 사용해. 동기적인 방식으로 작동하며, 블로킹 API를 사용하는데 이게 많은 사용자를 처리하는 애플리케이션에서는 성능 문제가 발생할 수 있어. 그래도 대부분의 경우에는 동기적인 코드를 작성하기 쉽고 이해하기도 쉬워. 또한 기존의 Spring MVC 애플리케이션을 업그레이드하기 쉽고, 많은 개발자들이 익숙해.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebFlux는 논블로킹 I/O를 기반으로 하는 리액티브 프로그래밍 모델을 사용해. 논블로킹 API를 사용하기 때문에 더 많은 동시 사용자를 처리할 수 있고, 높은 처리량과 낮은 지연 시간을 제공할 수 있어. 그래도 리액티브 프로그래밍은 기존의 동기적인 방식과는 다르게 동작하니까 학습 곡선이 높을 수 있어. 또한 이전 버전의 스프링에서 WebFlux를 사용하려면 많은 코드를 변경해야 해. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까 선택할 때는 다음과 같은 요소를 고려해봐.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동기적인 코드 작성 경험이 많다면 Web MVC를 선택할 수 있어.&lt;/li&gt;
&lt;li&gt;높은 동시 사용자 및 성능 요구 사항이 있다면 WebFlux를 선택할 수 있어.&lt;/li&gt;
&lt;li&gt;기존의 Spring MVC 애플리케이션을 업그레이드할 계획이 있다면 Web MVC를 선택할 수 있어.&lt;/li&gt;
&lt;li&gt;리액티브 프로그래밍 경험이 있다면 WebFlux를 선택할 수 있어.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 고려하면 적합한 옵션을 선택할 수 있을 거야. &lt;/p&gt;</description>
      <category>Develop/Back-End</category>
      <category>Bio</category>
      <category>NIO</category>
      <category>spring</category>
      <category>Webflux</category>
      <category>webflux vs webmvc</category>
      <category>webmvc</category>
      <category>동기</category>
      <category>비동기</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/8</guid>
      <comments>https://djlife.tistory.com/8#entry8comment</comments>
      <pubDate>Thu, 2 Mar 2023 21:34:06 +0900</pubDate>
    </item>
    <item>
      <title>React 로 롤 전적 통계 사이트를 만들어보자! - 3</title>
      <link>https://djlife.tistory.com/7</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;logo.png&quot; data-origin-width=&quot;4167&quot; data-origin-height=&quot;4167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rfao9/btrYjmSfIU5/VtuY6kYZuLHjVSNKyvCiW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rfao9/btrYjmSfIU5/VtuY6kYZuLHjVSNKyvCiW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rfao9/btrYjmSfIU5/VtuY6kYZuLHjVSNKyvCiW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRfao9%2FbtrYjmSfIU5%2FVtuY6kYZuLHjVSNKyvCiW1%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;4167&quot; height=&quot;4167&quot; data-filename=&quot;logo.png&quot; data-origin-width=&quot;4167&quot; data-origin-height=&quot;4167&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;(BE개발자 두명이서 진행했으며 저는 프론트를 맡았고 BE나 Devops는 어려움 겪을 때 지원하며 프로젝트를 끌고 갔다)&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;또 BE개발자 이다보니 자신있게 시작했지만 상당히 부족함이 많은걸 알게 되었다  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간마다 공부한 내용도 정리하고 블로그에 글도 남기고 싶었는데..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여유가 너무 없었다.(아직 구현 안된 기능도 많으며 product 키가 아니고 personerkey이기 때문에 조회 제한도 있는 상황 참고 바란다.)&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;소스는 github 공유해놓았다.  &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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/DongJu-Na&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1675699850023&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;profile&quot; data-og-title=&quot;DongJu-Na - Overview&quot; data-og-description=&quot;Hi. DongJu-Na has 11 repositories available. Follow their code on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/DongJu-Na&quot; data-og-url=&quot;https://github.com/DongJu-Na&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ef5OVT/hyRxNs5BKQ/vHuvbb0sZkKVovcDLQVvg0/img.png?width=460&amp;amp;height=460&amp;amp;face=0_0_460_460&quot;&gt;&lt;a href=&quot;https://github.com/DongJu-Na&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/DongJu-Na&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ef5OVT/hyRxNs5BKQ/vHuvbb0sZkKVovcDLQVvg0/img.png?width=460&amp;amp;height=460&amp;amp;face=0_0_460_460');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;DongJu-Na - Overview&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Hi. DongJu-Na has 11 repositories available. Follow their code on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1606&quot; data-origin-height=&quot;846&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CaCrh/btrYeZDx2GH/70gcB9ws2oG5728sYQyUH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CaCrh/btrYeZDx2GH/70gcB9ws2oG5728sYQyUH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CaCrh/btrYeZDx2GH/70gcB9ws2oG5728sYQyUH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCaCrh%2FbtrYeZDx2GH%2F70gcB9ws2oG5728sYQyUH1%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;1606&quot; height=&quot;846&quot; data-origin-width=&quot;1606&quot; data-origin-height=&quot;846&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;메인&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1840&quot; data-origin-height=&quot;936&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GadIe/btrYmtvQihg/CtdCpkpB2kh2X6gc5KuqfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GadIe/btrYmtvQihg/CtdCpkpB2kh2X6gc5KuqfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GadIe/btrYmtvQihg/CtdCpkpB2kh2X6gc5KuqfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGadIe%2FbtrYmtvQihg%2FCtdCpkpB2kh2X6gc5KuqfK%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;1840&quot; height=&quot;936&quot; data-origin-width=&quot;1840&quot; data-origin-height=&quot;936&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;전적통계&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1343&quot; data-origin-height=&quot;964&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wZLWI/btrYidVz6CA/CkNGaKibKRI2aYRu6Vz4Tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wZLWI/btrYidVz6CA/CkNGaKibKRI2aYRu6Vz4Tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wZLWI/btrYidVz6CA/CkNGaKibKRI2aYRu6Vz4Tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwZLWI%2FbtrYidVz6CA%2FCkNGaKibKRI2aYRu6Vz4Tk%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;1343&quot; height=&quot;964&quot; data-origin-width=&quot;1343&quot; data-origin-height=&quot;964&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;랭킹&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1237&quot; data-origin-height=&quot;876&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/safjr/btrYlv1Kw0X/h7FQ6UMpm2wq0RPJ0adRX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/safjr/btrYlv1Kw0X/h7FQ6UMpm2wq0RPJ0adRX1/img.png&quot; data-alt=&quot;커뮤니티&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/safjr/btrYlv1Kw0X/h7FQ6UMpm2wq0RPJ0adRX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsafjr%2FbtrYlv1Kw0X%2Fh7FQ6UMpm2wq0RPJ0adRX1%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;1237&quot; height=&quot;876&quot; data-origin-width=&quot;1237&quot; data-origin-height=&quot;876&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;커뮤니티&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1431&quot; data-origin-height=&quot;919&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btvg0I/btrYmzbLJvG/JqgZUJJbtZIbe3cip1P49K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btvg0I/btrYmzbLJvG/JqgZUJJbtZIbe3cip1P49K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btvg0I/btrYmzbLJvG/JqgZUJJbtZIbe3cip1P49K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtvg0I%2FbtrYmzbLJvG%2FJqgZUJJbtZIbe3cip1P49K%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;1431&quot; height=&quot;919&quot; data-origin-width=&quot;1431&quot; data-origin-height=&quot;919&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;게시글 상세&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;809&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAtDKn/btrYj0HWYDv/I2zWOsrhvocs3Klc5h6VQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAtDKn/btrYj0HWYDv/I2zWOsrhvocs3Klc5h6VQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAtDKn/btrYj0HWYDv/I2zWOsrhvocs3Klc5h6VQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAtDKn%2FbtrYj0HWYDv%2FI2zWOsrhvocs3Klc5h6VQ1%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;979&quot; height=&quot;809&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;809&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;로그인/회원가입&lt;/p&gt;</description>
      <category>Develop/Front-End</category>
      <category>fow.kr</category>
      <category>lol</category>
      <category>node</category>
      <category>op.gg</category>
      <category>React</category>
      <category>react-router-dom</category>
      <category>Recoil</category>
      <category>롤</category>
      <category>리그오브레전드</category>
      <category>리액트</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/7</guid>
      <comments>https://djlife.tistory.com/7#entry7comment</comments>
      <pubDate>Tue, 7 Feb 2023 01:17:36 +0900</pubDate>
    </item>
    <item>
      <title>삼각형의 완성조건</title>
      <link>https://djlife.tistory.com/6</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&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;합니다.&lt;/p&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;긴&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;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;삼각형의&amp;nbsp;세&amp;nbsp;변의&amp;nbsp;길이가&amp;nbsp;담긴&amp;nbsp;배열&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;sides&lt;/span&gt;이&amp;nbsp;매개변수로&amp;nbsp;주어집니다.&amp;nbsp;세&amp;nbsp;변으로&amp;nbsp;삼각형을&amp;nbsp;만들&amp;nbsp;수&amp;nbsp;있다면&amp;nbsp;1,&amp;nbsp;만들&amp;nbsp;수&amp;nbsp;없다면&amp;nbsp;2를&amp;nbsp;return하도록&amp;nbsp;solution&amp;nbsp;함수를&amp;nbsp;완성해주세요.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제한사항 &lt;br /&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;sides&lt;/span&gt;의 원소는 자연수입니다. &lt;br /&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;sides&lt;/span&gt;의 길이는 3입니다. &lt;br /&gt;1 &amp;le; &lt;span style=&quot;background-color: #dddddd;&quot;&gt;sides&lt;/span&gt;의 원소 &amp;le; 1,000&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;table style=&quot;border-collapse: collapse; width: 27.093%; height: 85px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;sides&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;[1, 2, 3]&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;[3, 6, 2]&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;[199, 72, 222]&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력&amp;nbsp;예&amp;nbsp;설명 &lt;br /&gt;&lt;br /&gt;입출력&amp;nbsp;예&amp;nbsp;#1 &lt;br /&gt;가장&amp;nbsp;큰&amp;nbsp;변인&amp;nbsp;3이&amp;nbsp;나머지&amp;nbsp;두&amp;nbsp;변의&amp;nbsp;합&amp;nbsp;3과&amp;nbsp;같으므로&amp;nbsp;삼각형을&amp;nbsp;완성할&amp;nbsp;수&amp;nbsp;없습니다.&amp;nbsp;따라서&amp;nbsp;2를&amp;nbsp;return합니다. &lt;br /&gt;&lt;br /&gt;입출력&amp;nbsp;예&amp;nbsp;#2 &lt;br /&gt;가장&amp;nbsp;큰&amp;nbsp;변인&amp;nbsp;6이&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;2를&amp;nbsp;return합니다. &lt;br /&gt;&lt;br /&gt;입출력&amp;nbsp;예&amp;nbsp;#3 &lt;br /&gt;가장&amp;nbsp;큰&amp;nbsp;변인&amp;nbsp;222가&amp;nbsp;나머지&amp;nbsp;두&amp;nbsp;변의&amp;nbsp;합&amp;nbsp;271보다&amp;nbsp;작으므로&amp;nbsp;삼각형을&amp;nbsp;완성할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;따라서&amp;nbsp;1을&amp;nbsp;return합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672968431872&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import  java.util.*;
    
class Solution {
    
    public int solution(int[] sides) {
        int answer = 0;
        Arrays.sort(sides);
        if((sides[0] + sides[1]) &amp;gt; sides[2])
            answer = 1;
        else
            answer = 2;
            
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-category=&quot;correctness&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr data-testcase-id=&quot;155646&quot;&gt;
&lt;td&gt;테스트 1 &lt;span style=&quot;color: #000000;&quot;&gt;〉&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;통과 (0.45ms, 78.9MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-testcase-id=&quot;155647&quot;&gt;
&lt;td&gt;테스트 2 &lt;span style=&quot;color: #000000;&quot;&gt;〉&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;통과 (0.32ms, 74.6MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-testcase-id=&quot;155648&quot;&gt;
&lt;td&gt;테스트 3 &lt;span style=&quot;color: #000000;&quot;&gt;〉&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;통과 (0.45ms, 73.7MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-testcase-id=&quot;155649&quot;&gt;
&lt;td&gt;테스트 4 &lt;span style=&quot;color: #000000;&quot;&gt;〉&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;통과 (0.35ms, 79.7MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-testcase-id=&quot;155650&quot;&gt;
&lt;td&gt;테스트 5 &lt;span style=&quot;color: #000000;&quot;&gt;〉&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;통과 (0.45ms, 72.2MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-testcase-id=&quot;155651&quot;&gt;
&lt;td&gt;테스트 6 &lt;span style=&quot;color: #000000;&quot;&gt;〉&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;통과 (0.45ms, 77.5MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-testcase-id=&quot;155652&quot;&gt;
&lt;td&gt;테스트 7 &lt;span style=&quot;color: #000000;&quot;&gt;〉&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;통과 (0.37ms, 70.3MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-testcase-id=&quot;155653&quot;&gt;
&lt;td&gt;테스트 8 &lt;span style=&quot;color: #000000;&quot;&gt;〉&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;통과 (1.30ms, 82.1MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-testcase-id=&quot;155654&quot;&gt;
&lt;td&gt;테스트 9 &lt;span style=&quot;color: #000000;&quot;&gt;〉&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;통과 (0.31ms, 78MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;채점 결과&lt;/div&gt;
&lt;div&gt;정확성: 100.0&lt;/div&gt;
&lt;div&gt;합계: 100.0 / 100.0&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>다이소/코딩테스트문제풀이</category>
      <category>lv0</category>
      <category>삼각형의 완성조건</category>
      <category>알고리즘</category>
      <category>코딩테스트</category>
      <category>프로그래머스</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/6</guid>
      <comments>https://djlife.tistory.com/6#entry6comment</comments>
      <pubDate>Fri, 6 Jan 2023 10:31:47 +0900</pubDate>
    </item>
    <item>
      <title>React 로 롤 전적 통계 사이트를 만들어보자! - 2</title>
      <link>https://djlife.tistory.com/5</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;React-icon.svg.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1043&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1lrNy/btrUul3MFov/RivjWYAtKk23eTXaEHWXnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1lrNy/btrUul3MFov/RivjWYAtKk23eTXaEHWXnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1lrNy/btrUul3MFov/RivjWYAtKk23eTXaEHWXnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1lrNy%2FbtrUul3MFov%2FRivjWYAtKk23eTXaEHWXnk%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;1200&quot; height=&quot;1043&quot; data-filename=&quot;React-icon.svg.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1043&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 개발 환경 설정은 전 글을 참고하길.. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://djlife.tistory.com/4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://djlife.tistory.com/4&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1671871835285&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;React 로 롤 전적 통계 사이트를 만들어보자! - 1&quot; data-og-description=&quot;소스 편집 툴은 비쥬얼 스튜디오 코드를 이용하려 한다. 프로그램이 가볍고 다양한 기능을 지원해서 추천.  이 게시물은 React , Node.js , NPM , CRA ... 등등 프론트엔드 기본 지식이 있는 사람이 볼 &quot; data-og-host=&quot;djlife.tistory.com&quot; data-og-source-url=&quot;https://djlife.tistory.com/4&quot; data-og-url=&quot;https://djlife.tistory.com/4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bMVRHf/hyQ1q6wDNZ/ibMpTpDePeqD7OcpgyOuFK/img.png?width=800&amp;amp;height=695&amp;amp;face=0_0_800_695,https://scrap.kakaocdn.net/dn/rUzYc/hyQZOup0wC/KKbQbErkVKKl2223hP1YKk/img.png?width=800&amp;amp;height=695&amp;amp;face=0_0_800_695,https://scrap.kakaocdn.net/dn/b9Cvod/hyQZQeHyzR/0QeOtI9h9KOMRkXWklJA80/img.png?width=1900&amp;amp;height=1002&amp;amp;face=0_0_1900_1002&quot;&gt;&lt;a href=&quot;https://djlife.tistory.com/4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://djlife.tistory.com/4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bMVRHf/hyQ1q6wDNZ/ibMpTpDePeqD7OcpgyOuFK/img.png?width=800&amp;amp;height=695&amp;amp;face=0_0_800_695,https://scrap.kakaocdn.net/dn/rUzYc/hyQZOup0wC/KKbQbErkVKKl2223hP1YKk/img.png?width=800&amp;amp;height=695&amp;amp;face=0_0_800_695,https://scrap.kakaocdn.net/dn/b9Cvod/hyQZQeHyzR/0QeOtI9h9KOMRkXWklJA80/img.png?width=1900&amp;amp;height=1002&amp;amp;face=0_0_1900_1002');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;React 로 롤 전적 통계 사이트를 만들어보자! - 1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소스 편집 툴은 비쥬얼 스튜디오 코드를 이용하려 한다. 프로그램이 가볍고 다양한 기능을 지원해서 추천.  이 게시물은 React , Node.js , NPM , CRA ... 등등 프론트엔드 기본 지식이 있는 사람이 볼&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;djlife.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;/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;
&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;p data-ke-size=&quot;size16&quot;&gt;1. React 프로젝트 디렉토리 설명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. React 필요 설치 라이브러리 소개&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 리그오브레전드(롤) 데이터 받아오는 방법&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. React 프로젝트 디렉토리 설명&lt;/b&gt;&lt;/h2&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;193&quot; data-origin-height=&quot;187&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FW2Cg/btrUunOc13y/wtzAuOErs0vLFX4KytjUuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FW2Cg/btrUunOc13y/wtzAuOErs0vLFX4KytjUuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FW2Cg/btrUunOc13y/wtzAuOErs0vLFX4KytjUuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFW2Cg%2FbtrUunOc13y%2FwtzAuOErs0vLFX4KytjUuk%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;193&quot; height=&quot;187&quot; data-origin-width=&quot;193&quot; data-origin-height=&quot;187&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 글에서 npx create-react-app (이하 CRA ) 명령어를 통해&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react 프로젝트를 신규로 구성하였다.&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;동작원리를 이해하기 쉬울 것 같아 간략하게 설명하고 넘어가겠다  &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;node_modules&lt;/b&gt; 폴더는 CRA를 구성하는 모든 패키지 소스 코드가 존재하는 폴더이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;public &lt;/b&gt;폴더는 사이트의 웹 액세스 가능한 루트를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;src&amp;nbsp;&lt;/b&gt;폴더는 빌드를 만드는 데 사용할 작업 파일이 포함되는 폴더이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;package.json&lt;/b&gt; 파일은 CRA 기본 패키지 외 추가로 설치된 라이브러리/패키지 정보(종류, 버전)가 기록되는 파일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;package-lock.json&lt;/b&gt; 파일은 npm&amp;nbsp;이나&amp;nbsp;yarn이&amp;nbsp;알아서&amp;nbsp;관리해주는&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;&lt;b&gt;README.md&lt;/b&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;파일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;.gitignore&lt;/b&gt; 파일은 git을 통해 배포할 때 제외할 파일을 기재하는 파일이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. React 필요 설치 라이브러리 소개&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;46&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdLu7t/btrUxdDW6Be/T6CDYZEALShTzJAGIMaHck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdLu7t/btrUxdDW6Be/T6CDYZEALShTzJAGIMaHck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdLu7t/btrUxdDW6Be/T6CDYZEALShTzJAGIMaHck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdLu7t%2FbtrUxdDW6Be%2FT6CDYZEALShTzJAGIMaHck%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;234&quot; height=&quot;46&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;46&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;212&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp7m8k/btrUuAta9Tw/zzFuCK9K1ggCKAprvKhP30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp7m8k/btrUuAta9Tw/zzFuCK9K1ggCKAprvKhP30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp7m8k/btrUuAta9Tw/zzFuCK9K1ggCKAprvKhP30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp7m8k%2FbtrUuAta9Tw%2FzzFuCK9K1ggCKAprvKhP30%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;212&quot; height=&quot;44&quot; data-origin-width=&quot;212&quot; data-origin-height=&quot;44&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;394&quot; data-origin-height=&quot;137&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PAVur/btrUuXWb3Yn/efwUWH3tUUGy1ju4OCjqmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PAVur/btrUuXWb3Yn/efwUWH3tUUGy1ju4OCjqmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PAVur/btrUuXWb3Yn/efwUWH3tUUGy1ju4OCjqmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPAVur%2FbtrUuXWb3Yn%2FefwUWH3tUUGy1ju4OCjqmk%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;394&quot; height=&quot;137&quot; data-origin-width=&quot;394&quot; data-origin-height=&quot;137&quot;/&gt;&lt;/span&gt;&lt;/figure&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ReactRouterDom은 &lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;신규 페이지를 불러오지 않는 상황에서 각각의 url에 따라 선택된 데이터를 하나의 페이지에서 렌더링 해주는 라이브러리이다.&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 style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;AXIOS는 브라우저와 node.js에서 사용할 수 있는 Promise 기반 HTTP 클라이언트 라이브러리이다.&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&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 style=&quot;color: #666666;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;Recoil은 상태관리 라이브러리인데 추후 소스를 작성하면서 설명하도록 하겠다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span&gt;3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;리그오브레전드(롤) 데이터 받아오는 방법&lt;/b&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;Riot Developer Portal을 이용하자&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;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a href=&quot;https://developer.riotgames.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.riotgames.com/&lt;/a&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1671876218225&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Riot Developer Portal&quot; data-og-description=&quot;About the Riot Games API With this site we hope to provide the League of Legends developer community with access to game data in a secure and reliable way. This is just part of our ongoing effort to respond to players' and developers' requests for data and&quot; data-og-host=&quot;developer.riotgames.com&quot; data-og-source-url=&quot;https://developer.riotgames.com/&quot; data-og-url=&quot;https://developer.riotgames.com/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://developer.riotgames.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.riotgames.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Riot Developer Portal&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;About the Riot Games API With this site we hope to provide the League of Legends developer community with access to game data in a secure and reliable way. This is just part of our ongoing effort to respond to players' and developers' requests for data and&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.riotgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;url를 클릭하여 로그인 후 api에 사용할 key를 발급받는다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1135&quot; data-origin-height=&quot;792&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9AAvM/btrUxoyCYmi/00b5PVH7QOP1mKzm1xhe20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9AAvM/btrUxoyCYmi/00b5PVH7QOP1mKzm1xhe20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9AAvM/btrUxoyCYmi/00b5PVH7QOP1mKzm1xhe20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9AAvM%2FbtrUxoyCYmi%2F00b5PVH7QOP1mKzm1xhe20%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;1135&quot; height=&quot;792&quot; data-origin-width=&quot;1135&quot; data-origin-height=&quot;792&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에 copy 버튼을 이용하여 발급받은 key를 적어놓고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상단에 api 버튼을 클릭하여 이용 가능한 api 리스트와 설명들을 확인 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;893&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK9rG8/btrUtGHDCNh/ejJkWdkKMoVtpdN39LyvVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK9rG8/btrUtGHDCNh/ejJkWdkKMoVtpdN39LyvVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK9rG8/btrUtGHDCNh/ejJkWdkKMoVtpdN39LyvVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK9rG8%2FbtrUtGHDCNh%2FejJkWdkKMoVtpdN39LyvVk%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;1689&quot; height=&quot;893&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;893&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;api 사용할 준비까지 마쳤다. &lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;* Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://ko.reactjs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ko.reactjs.org/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1671876278152&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;React &amp;ndash; 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리&quot; data-og-description=&quot;A JavaScript library for building user interfaces&quot; data-og-host=&quot;ko.reactjs.org&quot; data-og-source-url=&quot;https://ko.reactjs.org/&quot; data-og-url=&quot;https://ko.reactjs.org/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/BvHtY/hyQZInq8RX/u0GFKLvx255vyLK8XkQNTk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.reactjs.org/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/BvHtY/hyQZInq8RX/u0GFKLvx255vyLK8XkQNTk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;React &amp;ndash; 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A JavaScript library for building user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.reactjs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://reactrouter.com/en/6.6.1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://reactrouter.com/en/6.6.1&lt;/a&gt; ReactRouterDom&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1671875727986&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Home v6.6.1&quot; data-og-description=&quot;I'm on v5 The migration guide will help you migrate incrementally and keep shipping along the way. Or, do it all in one yolo commit! Either way, we've got you covered to start using the new features right away.&quot; data-og-host=&quot;reactrouter.com&quot; data-og-source-url=&quot;https://reactrouter.com/en/6.6.1&quot; data-og-url=&quot;https://reactrouter.com/en/6.6.1&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/yPObR/hyQ1gXaEnE/6zXef7TcRYx9lOwb7l35e0/img.png?width=1200&amp;amp;height=627&amp;amp;face=0_0_1200_627,https://scrap.kakaocdn.net/dn/OtXT4/hyQ1qrVRuy/PtnS1zD6UVpSvbK9sMLENk/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://reactrouter.com/en/6.6.1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://reactrouter.com/en/6.6.1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/yPObR/hyQ1gXaEnE/6zXef7TcRYx9lOwb7l35e0/img.png?width=1200&amp;amp;height=627&amp;amp;face=0_0_1200_627,https://scrap.kakaocdn.net/dn/OtXT4/hyQ1qrVRuy/PtnS1zD6UVpSvbK9sMLENk/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Home v6.6.1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I'm on v5 The migration guide will help you migrate incrementally and keep shipping along the way. Or, do it all in one yolo commit! Either way, we've got you covered to start using the new features right away.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;reactrouter.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://axios-http.com/kr/docs/intro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://axios-http.com/kr/docs/intro&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1671875748091&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;시작하기 |&amp;nbsp;Axios Docs&quot; data-og-description=&quot;시작하기 브라우저와 node.js에서 사용할 수 있는 Promise 기반 HTTP 클라이언트 라이브러리 Axios란? Axios는 node.js와 브라우저를 위한 Promise 기반 HTTP 클라이언트 입니다. 그것은 동형 입니다(동일한 코&quot; data-og-host=&quot;axios-http.com&quot; data-og-source-url=&quot;https://axios-http.com/kr/docs/intro&quot; data-og-url=&quot;https://axios-http.com/kr/docs/intro&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://axios-http.com/kr/docs/intro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://axios-http.com/kr/docs/intro&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;시작하기 |&amp;nbsp;Axios Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;시작하기 브라우저와 node.js에서 사용할 수 있는 Promise 기반 HTTP 클라이언트 라이브러리 Axios란? Axios는 node.js와 브라우저를 위한 Promise 기반 HTTP 클라이언트 입니다. 그것은 동형 입니다(동일한 코&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;axios-http.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://recoiljs.org/ko/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://recoiljs.org/ko/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1671875759493&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Recoil&quot; data-og-description=&quot;A state management library for React.&quot; data-og-host=&quot;recoiljs.org&quot; data-og-source-url=&quot;https://recoiljs.org/ko/&quot; data-og-url=&quot;https://recoiljs.org/ko/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PUQM0/hyQZFROgqv/I5XOzs1NKGpiKsQTGGPK30/img.png?width=1420&amp;amp;height=646&amp;amp;face=0_0_1420_646,https://scrap.kakaocdn.net/dn/JW5tQ/hyQZI12VDE/mbT5ZOUkrdhNOgP8EFItn0/img.png?width=1420&amp;amp;height=646&amp;amp;face=0_0_1420_646&quot;&gt;&lt;a href=&quot;https://recoiljs.org/ko/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://recoiljs.org/ko/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PUQM0/hyQZFROgqv/I5XOzs1NKGpiKsQTGGPK30/img.png?width=1420&amp;amp;height=646&amp;amp;face=0_0_1420_646,https://scrap.kakaocdn.net/dn/JW5tQ/hyQZI12VDE/mbT5ZOUkrdhNOgP8EFItn0/img.png?width=1420&amp;amp;height=646&amp;amp;face=0_0_1420_646');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Recoil&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A state management library for React.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;recoiljs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;본문 중 틀린 내용이 있으면 언제든지 말씀해주시면 수정하도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Develop/Front-End</category>
      <category>fow.kr</category>
      <category>lol</category>
      <category>node</category>
      <category>op.gg</category>
      <category>React</category>
      <category>react-router-dom</category>
      <category>Recoil</category>
      <category>롤</category>
      <category>리그오브레전드</category>
      <category>리액트</category>
      <author>알 수 없는 사용자</author>
      <guid isPermaLink="true">https://djlife.tistory.com/5</guid>
      <comments>https://djlife.tistory.com/5#entry5comment</comments>
      <pubDate>Sat, 24 Dec 2022 19:15:30 +0900</pubDate>
    </item>
  </channel>
</rss>