<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>사붐이개발일기</title>
    <link>https://devbeomstory.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 27 May 2026 14:37:43 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>sabeom</managingEditor>
    <image>
      <title>사붐이개발일기</title>
      <url>https://tistory1.daumcdn.net/tistory/5970656/attach/0adf18039b4044fcb6a1ed389386ee24</url>
      <link>https://devbeomstory.tistory.com</link>
    </image>
    <item>
      <title>[Obsidian] Obsidian으로 자동 Git Commit 하기</title>
      <link>https://devbeomstory.tistory.com/190</link>
      <description>&lt;p&gt;Obsidian에 정리한 문서를 Git으로 관리하고 싶다면 &lt;code&gt;Obsidian Git&lt;/code&gt; 플러그인을 활용하는 방법이 가장 간단합니다.&lt;br&gt;별도의 터미널 작업을 자주 하지 않아도 주기적으로 &lt;code&gt;commit&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;을 자동화할 수 있어서, 기록 흐름이 끊기지 않는 점이 특히 편했습니다.&lt;/p&gt;
&lt;p&gt;이번 글에서는 Obsidian에 Git Plugin을 설치하고, Vault를 GitHub 저장소와 연결한 뒤 자동 커밋 설정까지 적용하는 과정을 정리해보겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Obsidian에서 Git Plugin 설치하기&lt;/h2&gt;
&lt;p&gt;먼저 Obsidian에서 Community Plugin 기능을 활성화한 뒤 &lt;code&gt;Git&lt;/code&gt; 플러그인을 설치합니다.&lt;/p&gt;
&lt;h4&gt;1. Community Plugins 활성화&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Settings&lt;/code&gt;에서 &lt;code&gt;Community plugins&lt;/code&gt; 메뉴로 이동한 뒤 &lt;code&gt;Turn on community plugins&lt;/code&gt;를 선택합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;795&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc3xpl/dJMcabw7AGh/YyJj7f10WefMvK6Kf47odK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc3xpl/dJMcabw7AGh/YyJj7f10WefMvK6Kf47odK/img.png&quot; data-alt=&quot;Turn on community plugins 클릭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc3xpl/dJMcabw7AGh/YyJj7f10WefMvK6Kf47odK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc3xpl%2FdJMcabw7AGh%2FYyJj7f10WefMvK6Kf47odK%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;795&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;795&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Turn on community plugins 클릭&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4&gt;2. Browse 선택&lt;/h4&gt;
&lt;p&gt;플러그인 목록을 보기 위해 &lt;code&gt;Browse&lt;/code&gt;를 클릭합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;795&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R8qLD/dJMcag6h2SR/sUWoRP32SRQj480F8vJOFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R8qLD/dJMcag6h2SR/sUWoRP32SRQj480F8vJOFk/img.png&quot; data-alt=&quot;Browse 클릭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R8qLD/dJMcag6h2SR/sUWoRP32SRQj480F8vJOFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR8qLD%2FdJMcag6h2SR%2FsUWoRP32SRQj480F8vJOFk%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;1019&quot; height=&quot;795&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;795&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Browse 클릭&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4&gt;3. Git Plugin 검색&lt;/h4&gt;
&lt;p&gt;검색창에 &lt;code&gt;Git&lt;/code&gt;을 입력한 뒤, &lt;code&gt;Obsidian Git&lt;/code&gt; 플러그인을 선택합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1017&quot; data-origin-height=&quot;795&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/natjZ/dJMcadhpZij/yTtBXvNPoA0UHEz5dkkQK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/natjZ/dJMcadhpZij/yTtBXvNPoA0UHEz5dkkQK1/img.png&quot; data-alt=&quot;Plugin 검색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/natjZ/dJMcadhpZij/yTtBXvNPoA0UHEz5dkkQK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnatjZ%2FdJMcadhpZij%2FyTtBXvNPoA0UHEz5dkkQK1%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;1017&quot; height=&quot;795&quot; data-origin-width=&quot;1017&quot; data-origin-height=&quot;795&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Plugin 검색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4&gt;4. Plugin 설치&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Install&lt;/code&gt; 버튼을 눌러 플러그인을 설치합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;796&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oacj6/dJMcahxm52a/EsQ38vII1KjbVdizcWkp41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oacj6/dJMcahxm52a/EsQ38vII1KjbVdizcWkp41/img.png&quot; data-alt=&quot;Plugin Install&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oacj6/dJMcahxm52a/EsQ38vII1KjbVdizcWkp41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Foacj6%2FdJMcahxm52a%2FEsQ38vII1KjbVdizcWkp41%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;1019&quot; height=&quot;796&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;796&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Plugin Install&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4&gt;5. Plugin 활성화&lt;/h4&gt;
&lt;p&gt;설치가 끝나면 &lt;code&gt;Enable&lt;/code&gt;을 눌러 플러그인을 활성화합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;795&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b53UMC/dJMcafl01WJ/aGYb0tsmMEBkMK1jOV3kQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b53UMC/dJMcafl01WJ/aGYb0tsmMEBkMK1jOV3kQ1/img.png&quot; data-alt=&quot;Plugin Enable&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b53UMC/dJMcafl01WJ/aGYb0tsmMEBkMK1jOV3kQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb53UMC%2FdJMcafl01WJ%2FaGYb0tsmMEBkMK1jOV3kQ1%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;1019&quot; height=&quot;795&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;795&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Plugin Enable&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Git 저장소 연동하기&lt;/h2&gt;
&lt;p&gt;플러그인 설치가 끝났다면, 이제 Obsidian Vault를 Git 저장소와 연결해야 합니다.&lt;/p&gt;
&lt;h4&gt;1. Vault 루트에 &lt;code&gt;.gitignore&lt;/code&gt; 파일 만들기&lt;/h4&gt;
&lt;p&gt;먼저 Vault 경로에 &lt;code&gt;.gitignore&lt;/code&gt; 파일을 생성합니다.&lt;br&gt;사용 중인 환경에 따라 제외할 파일은 달라질 수 있으니, 자신의 Vault 구조에 맞게 관리하면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdED8r/dJMcai32GH3/RfO4ySDNgfV8snz3UUBHM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdED8r/dJMcai32GH3/RfO4ySDNgfV8snz3UUBHM1/img.png&quot; data-alt=&quot;Add .gitignore&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdED8r/dJMcai32GH3/RfO4ySDNgfV8snz3UUBHM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdED8r%2FdJMcai32GH3%2FRfO4ySDNgfV8snz3UUBHM1%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;701&quot; height=&quot;524&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Add .gitignore&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4&gt;2. Git 저장소 초기 연결&lt;/h4&gt;
&lt;p&gt;이제 Vault 경로에서 아래 명령어를 실행해 Git 저장소를 연결합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git init
git add .
git commit -m &amp;quot;git init&amp;quot;
git branch -M main
git remote add origin &amp;quot;깃허브 저장소 주소&amp;quot;
git push -u origin main&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;각 명령어의 의미는 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git init&lt;/code&gt;&lt;br&gt;현재 폴더를 Git 저장소로 초기화합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git add .&lt;/code&gt;&lt;br&gt;현재 파일들을 스테이징합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git commit -m &amp;quot;git init&amp;quot;&lt;/code&gt;&lt;br&gt;첫 커밋을 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch -M main&lt;/code&gt;&lt;br&gt;현재 브랜치 이름을 &lt;code&gt;main&lt;/code&gt;으로 변경합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git remote add origin &amp;quot;깃허브 저장소 주소&amp;quot;&lt;/code&gt;&lt;br&gt;원격 저장소를 등록합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push -u origin main&lt;/code&gt;&lt;br&gt;원격 저장소에 최초 푸시를 하고, 이후 기본 업스트림 브랜치로 설정합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;Git 자동 커밋 설정하기&lt;/h2&gt;
&lt;p&gt;저는 아래처럼 설정해서 사용하고 있습니다.&lt;/p&gt;
&lt;h4&gt;1. 30분마다 자동 Commit &amp;amp; Push&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;commit&lt;/code&gt;과 &lt;code&gt;sync&lt;/code&gt;가 주기적으로 실행되도록 &lt;code&gt;30분&lt;/code&gt; 간격으로 설정했습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Auto commit-and-sync interval: &lt;code&gt;30&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 10분마다 자동 Pull&lt;/h4&gt;
&lt;p&gt;원격 저장소 변경사항을 너무 늦지 않게 가져오기 위해 &lt;code&gt;10분&lt;/code&gt; 간격으로 &lt;code&gt;pull&lt;/code&gt; 설정을 적용했습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Auto pull interval: &lt;code&gt;10&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;795&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5WkII/dJMcabjDvD0/loXV1cLcQjo27M0MES9BT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5WkII/dJMcabjDvD0/loXV1cLcQjo27M0MES9BT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5WkII/dJMcabjDvD0/loXV1cLcQjo27M0MES9BT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5WkII%2FdJMcabjDvD0%2FloXV1cLcQjo27M0MES9BT1%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;1020&quot; height=&quot;795&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;795&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이렇게 설정해두면 기록에만 집중해도 주기적으로 변경 사항이 정리되기 때문에, 수동으로 커밋하고 푸시하는 번거로움이 많이 줄어듭니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;정리한 내용을 Git에 올릴 때마다 별도로 터미널을 열고 커밋하는 과정이 생각보다 흐름을 많이 끊었습니다.&lt;br&gt;그런데 Obsidian에서 Git Plugin으로 자동화해두니 시간도 줄고, 기록에만 집중할 수 있어서 꽤 만족스러웠습니다.&lt;/p&gt;
&lt;p&gt;Obsidian을 메모 도구를 넘어 지식 저장소처럼 운영하고 있다면, Git Plugin은 한 번쯤 꼭 써볼 만한 플러그인이라고 생각합니다.&lt;/p&gt;</description>
      <category>DevTools/Obsidian</category>
      <author>sabeom</author>
      <guid isPermaLink="true">https://devbeomstory.tistory.com/190</guid>
      <comments>https://devbeomstory.tistory.com/190#entry190comment</comments>
      <pubDate>Mon, 20 Apr 2026 10:54:34 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Global Exception Handler (Controller Advice)</title>
      <link>https://devbeomstory.tistory.com/169</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid;&quot; 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;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;h3 style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid;&quot; 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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;에러 핸들러&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1733271968006&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * Handle all uncaught exceptions.
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity&amp;lt;ErrorResponse&amp;gt; handleGenericException(Exception ex) {
        log.error(&quot;Unhandled exception occurred: {}&quot;, ex.getMessage(), ex);
        ErrorResponse response = new ErrorResponse(
                HttpStatus.INTERNAL_SERVER_ERROR.value(),
                &quot;An unexpected error occurred.&quot;,
                LocalDateTime.now()
        );
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
    }

    /**
     * Handle custom not found exceptions.
     */
    @ExceptionHandler(BizExceptionMessage.class)
    public ResponseEntity&amp;lt;ErrorResponse&amp;gt; handleBizExceptionMessage(BizExceptionMessage ex) {
        log.warn(&quot;Resource not found: {}&quot;, ex.getMessage());
        ErrorResponse response = new ErrorResponse(
                HttpStatus.NOT_FOUND.value(),
                ex.getMessage(),
                LocalDateTime.now()
        );
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }

    /**
     * Handle validation errors from @Valid annotations.
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity&amp;lt;ValidationErrorResponse&amp;gt; handleValidationExceptions(MethodArgumentNotValidException ex) {
        List&amp;lt;Violation&amp;gt; violations = ex.getBindingResult().getFieldErrors()
                .stream()
                .map(this::toViolation)
                .collect(Collectors.toList());

        ValidationErrorResponse response = new ValidationErrorResponse(
                HttpStatus.BAD_REQUEST.value(),
                &quot;Validation failed&quot;,
                LocalDateTime.now(),
                violations
        );

        log.debug(&quot;Validation errors: {}&quot;, violations);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
    }

    /**
     * Handle validation errors from @Validated annotations or ConstraintViolation.
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity&amp;lt;ValidationErrorResponse&amp;gt; handleConstraintViolation(ConstraintViolationException ex) {
        List&amp;lt;Violation&amp;gt; violations = ex.getConstraintViolations()
                .stream()
                .map(cv -&amp;gt; new Violation(
                        cv.getPropertyPath().toString(),
                        cv.getInvalidValue(),
                        cv.getMessage()
                ))
                .collect(Collectors.toList());

        ValidationErrorResponse response = new ValidationErrorResponse(
                HttpStatus.BAD_REQUEST.value(),
                &quot;Validation failed&quot;,
                LocalDateTime.now(),
                violations
        );

        log.debug(&quot;Constraint violations: {}&quot;, violations);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
    }

    private Violation toViolation(FieldError fieldError) {
        return new Violation(fieldError.getField(), fieldError.getRejectedValue(), fieldError.getDefaultMessage());
    }

    /**
     * Response structure for general errors.
     */
    public static class ErrorResponse {
        private final int status;
        private final String message;
        private final LocalDateTime timestamp;

        public ErrorResponse(int status, String message, LocalDateTime timestamp) {
            this.status = status;
            this.message = message;
            this.timestamp = timestamp;
        }

        // Getters
        public int getStatus() { return status; }
        public String getMessage() { return message; }
        public LocalDateTime getTimestamp() { return timestamp; }
    }

    /**
     * Response structure for validation errors.
     */
    public static class ValidationErrorResponse extends ErrorResponse {
        private final List&amp;lt;Violation&amp;gt; violations;

        public ValidationErrorResponse(int status, String message, LocalDateTime timestamp, List&amp;lt;Violation&amp;gt; violations) {
            super(status, message, timestamp);
            this.violations = violations;
        }

        // Getter
        public List&amp;lt;Violation&amp;gt; getViolations() { return violations; }
    }

    /**
     * Represents a single validation error.
     */
    public static class Violation {
        private final String fieldName;
        private final Object rejectedValue;
        private final String message;

        public Violation(String fieldName, Object rejectedValue, String message) {
            this.fieldName = fieldName;
            this.rejectedValue = rejectedValue;
            this.message = message;
        }

        // Getters
        public String getFieldName() { return fieldName; }
        public Object getRejectedValue() { return rejectedValue; }
        public String getMessage() { return message; }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&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;Exception: 예기치 못한 일반 오류 처리.&lt;/li&gt;
&lt;li&gt;CustomNotFoundException: 사용자 정의 예외 처리.&lt;/li&gt;
&lt;li&gt;MethodArgumentNotValidException: @Valid 유효성 검증 실패 처리.&lt;/li&gt;
&lt;li&gt;ConstraintViolationException: 유효성 검증 실패 (주로 @Validated에서 발생) 처리.&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;ErrorResponse: 일반 오류 응답 구조.&lt;/li&gt;
&lt;li&gt;ValidationErrorResponse: 검증 오류 응답 구조, 필드별 오류 세부 정보 포함.&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;각 예외 처리 블록에서 적절한 로깅(log.error, log.warn, log.debug).&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;Violation 클래스와 ValidationErrorResponse를 사용해 일관된 검증 오류 응답 제공.&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;/ul&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;커스텀 에러 메시지&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1733273507514&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class BizExceptionMessage extends RuntimeException {
    private int code;
    private ErrorType errorType;
    private String msgTypCod; //Q : Question, C : Critical, I : Information, E : Exclamation , B : system
    private String msgCaption;
    private Locale msgLocale;

    public BizExceptionMessage(ErrorType errorType) {
        super(errorType.getMessage());
        this.errorType = errorType;
        this.code = errorType.getCode();
        this.msgTypCod = &quot;&quot;;
        this.msgCaption = &quot;&quot;;
        this.msgLocale = Locale.KOREA;
    }

    public BizExceptionMessage(ErrorType errorType, Locale localeInfo) {
        super(errorType.getMessage());
        this.errorType = errorType;
        this.code = errorType.getCode();
        this.msgTypCod = &quot;&quot;;
        this.msgCaption = &quot;&quot;;
        this.msgLocale = localeInfo;
    }

    public BizExceptionMessage(ErrorType errorType, String subMessage) {
        super(errorType.getMessage() + &quot; (&quot; + subMessage + &quot;)&quot;);
        this.errorType = errorType;
        this.code = errorType.getCode();
        this.msgTypCod = &quot;&quot;;
        this.msgCaption = &quot;&quot;;
        this.msgLocale = Locale.KOREA;
    }

    public BizExceptionMessage(String msgTypCod, ErrorType errorType, String subMessage) {
        super(errorType.getMessage() + &quot; (&quot; + subMessage + &quot;)&quot;);
        this.errorType = errorType;
        this.code = errorType.getCode();
        this.msgTypCod = msgTypCod;
        this.msgCaption = &quot;&quot;;
        this.msgLocale = Locale.KOREA;
    }

    public BizExceptionMessage(String msgTypCod, ErrorType errorType, String subMessage, String msgCaption) {
        super(errorType.getMessage() + &quot; (&quot; + subMessage + &quot;)&quot;);
        this.errorType = errorType;
        this.code = errorType.getCode();
        this.msgTypCod = msgTypCod;
        this.msgCaption = msgCaption;
        this.msgLocale = Locale.KOREA;
    }

    public int getCode() {
        return code;
    }

    public String getMsgTypCod() {
        return msgTypCod;
    }

    public String getMsgCaption() {
        return msgCaption;
    }

    public ErrorType getErrorType() {
        return this.errorType;
    }

    public Locale getMsgLocale() {
        return msgLocale;
    }
}&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;에러타입 정의&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1733272227693&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public enum ErrorType {

    // 성공
    SUCCESS(0, &quot;Success&quot;, &quot;Operation completed successfully&quot;, &quot;SUCCESS&quot;),

    // 인증 및 권한 오류 (10000 ~ 10999)
    INVALID_CREDENTIALS(10001, &quot;Invalid credentials&quot;, &quot;The provided username or password is incorrect&quot;, &quot;INVALID_CREDENTIALS&quot;),
    UNAUTHORIZED_ACCESS(10002, &quot;Unauthorized access&quot;, &quot;You do not have the required permissions to access this resource&quot;, &quot;UNAUTHORIZED_ACCESS&quot;),
    TOKEN_EXPIRED(10003, &quot;Token expired&quot;, &quot;The authentication token has expired&quot;, &quot;TOKEN_EXPIRED&quot;),
    TOKEN_INVALID(10004, &quot;Invalid token&quot;, &quot;The provided token is invalid&quot;, &quot;TOKEN_INVALID&quot;),
    ACCOUNT_LOCKED(10005, &quot;Account locked&quot;, &quot;This account is locked due to too many failed login attempts&quot;, &quot;ACCOUNT_LOCKED&quot;),

    // 입력 값 오류 (20000 ~ 20999)
    INVALID_INPUT(20001, &quot;Invalid input&quot;, &quot;One or more input values are invalid&quot;, &quot;INVALID_INPUT&quot;),
    MISSING_REQUIRED_FIELD(20002, &quot;Missing required field&quot;, &quot;A required field is missing in the request&quot;, &quot;MISSING_REQUIRED_FIELD&quot;),
    INVALID_FORMAT(20003, &quot;Invalid format&quot;, &quot;The input format is incorrect&quot;, &quot;INVALID_FORMAT&quot;),
    DUPLICATE_ENTRY(20004, &quot;Duplicate entry&quot;, &quot;The provided value already exists&quot;, &quot;DUPLICATE_ENTRY&quot;),

    // 데이터베이스 오류 (30000 ~ 30999)
    DATABASE_ERROR(30001, &quot;Database error&quot;, &quot;An error occurred while interacting with the database&quot;, &quot;DATABASE_ERROR&quot;),
    DATA_NOT_FOUND(30002, &quot;Data not found&quot;, &quot;The requested data could not be found in the database&quot;, &quot;DATA_NOT_FOUND&quot;),
    CONSTRAINT_VIOLATION(30003, &quot;Constraint violation&quot;, &quot;A database constraint was violated&quot;, &quot;CONSTRAINT_VIOLATION&quot;),
    QUERY_TIMEOUT(30004, &quot;Query timeout&quot;, &quot;The database query took too long to execute&quot;, &quot;QUERY_TIMEOUT&quot;),

    // 파일 관련 오류 (40000 ~ 40999)
    FILE_NOT_FOUND(40001, &quot;File not found&quot;, &quot;The requested file could not be located&quot;, &quot;FILE_NOT_FOUND&quot;),
    FILE_UPLOAD_ERROR(40002, &quot;File upload error&quot;, &quot;An error occurred while uploading the file&quot;, &quot;FILE_UPLOAD_ERROR&quot;),
    FILE_SIZE_EXCEEDED(40003, &quot;File size exceeded&quot;, &quot;The uploaded file exceeds the maximum allowed size&quot;, &quot;FILE_SIZE_EXCEEDED&quot;),
    UNSUPPORTED_FILE_FORMAT(40004, &quot;Unsupported file format&quot;, &quot;The uploaded file format is not supported&quot;, &quot;UNSUPPORTED_FILE_FORMAT&quot;),

    // 네트워크 및 통신 오류 (50000 ~ 50999)
    NETWORK_ERROR(50001, &quot;Network error&quot;, &quot;An error occurred while communicating with the server&quot;, &quot;NETWORK_ERROR&quot;),
    SERVICE_UNAVAILABLE(50002, &quot;Service unavailable&quot;, &quot;The requested service is temporarily unavailable&quot;, &quot;SERVICE_UNAVAILABLE&quot;),
    TIMEOUT_ERROR(50003, &quot;Timeout error&quot;, &quot;The request timed out while waiting for a response&quot;, &quot;TIMEOUT_ERROR&quot;),

    // 서버 내부 오류 (60000 ~ 60999)
    INTERNAL_SERVER_ERROR(60001, &quot;Internal server error&quot;, &quot;An unexpected error occurred on the server&quot;, &quot;INTERNAL_SERVER_ERROR&quot;),
    NULL_POINTER_EXCEPTION(60002, &quot;Null pointer exception&quot;, &quot;A null pointer exception occurred&quot;, &quot;NULL_POINTER_EXCEPTION&quot;),
    ILLEGAL_STATE(60003, &quot;Illegal state&quot;, &quot;The application encountered an illegal state&quot;, &quot;ILLEGAL_STATE&quot;),
    CONFIGURATION_ERROR(60004, &quot;Configuration error&quot;, &quot;A configuration issue was detected&quot;, &quot;CONFIGURATION_ERROR&quot;),

    // 기본 및 알 수 없는 오류 (90000 ~ 90999)
    UNKNOWN_ERROR(90001, &quot;Unknown error&quot;, &quot;An unknown error occurred&quot;, &quot;UNKNOWN_ERROR&quot;);

    private final int code;
    private final String message;
    private final String detailMessage;
    private final String messageKey;

    ErrorType(int code, String message, String detailMessage, String messageKey) {
        this.code = code;
        this.message = message;
        this.detailMessage = detailMessage;
        this.messageKey = messageKey;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    public String getDetailMessage() {
        return detailMessage;
    }

    public String getMessageKey() {
        return messageKey;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인증 및 권한 오류 (10000 ~ 10999)&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;입력 값 오류 (20000 ~ 20999)&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스 오류 (30000 ~ 30999)&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파일 관련 오류 (40000 ~ 40999)&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 및 통신 오류 (50000 ~ 50999)&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서버 내부 오류 (60000 ~ 60999)&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;알 수 없는 오류 (90000 ~ 90999)&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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>Spring</category>
      <author>sabeom</author>
      <guid isPermaLink="true">https://devbeomstory.tistory.com/169</guid>
      <comments>https://devbeomstory.tistory.com/169#entry169comment</comments>
      <pubDate>Wed, 4 Dec 2024 09:37:46 +0900</pubDate>
    </item>
    <item>
      <title>[JS/Svelte] Excel파일 다운로드 기능 구현하기 - Excel.js</title>
      <link>https://devbeomstory.tistory.com/164</link>
      <description>&lt;h3 style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid;&quot; 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;회사 프로젝트에서 정산현황의 기간 별 데이터를 엑셀 파일로 만들어 내려받게 해달라는 요구사항이 들어왔다. 엑셀파일 변환은 처음이라 여기저기 구글링하다 xlsx 라이브러리 보단 excel.js 가 좀 더 간단한것같아서 후자로 라이브러리를 선택했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 더 찾아보니 xlsx 라이브러리는 css가 유료라고 한다.&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;h3 style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;사용하기&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. exceljs 라이브러리 설치&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1723620550272&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install exceljs;&lt;/code&gt;&lt;/pre&gt;
&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;2. exceljs 객체 가져오기&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1723620592310&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import ExcelJS from 'exceljs';&lt;/code&gt;&lt;/pre&gt;
&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;3. workbook 객체 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑셀파일은 여러개의 sheet를 포함한다. workbook은 worksheet를 담는 그릇이다.&lt;/p&gt;
&lt;pre id=&quot;code_1723620775840&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const workbook = new ExcelJS.Workbook();&lt;/code&gt;&lt;/pre&gt;
&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;4. worksheet 객체 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;worksheet는 엑셀파일에서 sheet에 해당한다.&lt;/p&gt;
&lt;pre id=&quot;code_1723620864568&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const worksheet = workbook.addWorksheet('정산데이터');&lt;/code&gt;&lt;/pre&gt;
&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;5. worksheet 컬럼명 등록&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;worksheet 첫번째 줄에 컬럼명을 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;header : 컬럼명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key : 데이터 key 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;style : 데이터 포맷 or style 설정&lt;/p&gt;
&lt;pre id=&quot;code_1723621001487&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;worksheet.columns = [
      {header: '순번', key: 'rowNum', style: {numFmt: '0'}},
      ...
      {header: '승인일자', key: 'appDt'},
      {header: '승인시간', key: 'appTm'},
      {header: '취소일자', key: 'ccDt'},
      {header: '취소시간', key: 'ccTm'},
      {header: '금액', key: 'amt'},
      {header: '과세', key: 'taxAmt'},
      {header: '비과세', key: 'taxFreeAmt'},
      {header: '일반수수료', key: 'generalFee'},
      {header: '일반부가세', key: 'generalVat'},
      {header: '입금금액', key: 'depositAmt'},
      {header: '정산일자', key: 'settlmntDt'}
    ];&lt;/code&gt;&lt;/pre&gt;
&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;6. worksheet 데이터 추가&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;worksheet 2번째줄 부터 데이터를 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1723621352710&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const data = {'rowNum' = 1, 'appDt' = '20240814', 'appTm' = '164011', ... }
worksheet.insertRows(2, data);&lt;/code&gt;&lt;/pre&gt;
&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;7. workbook 객체를 Blob 객체로 변환하여 다운받기&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1723621776097&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fileName = '파일명.xlsx';

workbook.xlsx.writeBuffer()
    .then((data) =&amp;gt; {
      const blob = new Blob([data], {type: &quot;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet&quot;});
      const url = window.URL.createObjectURL(blob);
      const anchor = document.createElement('a');
      anchor.href = url;
      anchor.download = fileName;
      anchor.click();
      window.URL.revokeObjectURL(url);
    })
    .catch((error) =&amp;gt; {
        console.error('Error creating Excel file:', error);
	});&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;h3 style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid;&quot; 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;서버에서 VO 값을 String으로 뿌려주니 excel로 변환했을때도 값들이 String으로 들어가 정렬이 안되는 문제가 있었다.&lt;br /&gt;number로 변경하려면 클라이언트에서 json을 int로 변경해주거나 서버에서 int로 보내주면된다. 나는 서버에서 int로 변경했다.&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;#&amp;nbsp; 24-08-21&lt;/b&gt;&lt;/h4&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;pre id=&quot;code_1724291401011&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;worksheet.columns = [
      {header: '순번', key: 'rowNum', style: {numFmt: '0', alignment: {horizontal: 'center'}}},
      ...
      {header: '결제자명', key: 'mpayMbrName', style: {alignment: {horizontal: 'center'}}},
      {header: '결제상태', key: 'padjStatDesc', style: {alignment: {horizontal: 'center'}}},
      {header: '승인일자', key: 'appDtDesc', width: 15, style: {alignment: {horizontal: 'center'}}},
      {header: '승인시간', key: 'appTmDesc', width: 15, style: {alignment: {horizontal: 'center'}}},
      {header: '취소일자', key: 'ccDtDesc', width: 15, style: {alignment: {horizontal: 'center'}}},
      {header: '취소시간', key: 'ccTmDesc', width: 15, style: {alignment: {horizontal: 'center'}}},
      {header: '금액', key: 'amt', style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
      {header: '과세', key: 'taxAmt', style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
      {header: '비과세', key: 'taxFreeAmt', style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
      {header: '일반수수료', key: 'generalFee', width: 10, style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
      {header: '일반부가세', key: 'generalVat', width: 10, style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
      {header: '입금금액', key: 'depositAmt', style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
      {header: '정산일자', key: 'settlmntDtDesc', width: 15, style: {alignment: {horizontal: 'center'}}}
    ];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;엑셀 데이터 변경&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724291430272&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 기존 JSON 데이터 + 가공데이터 추가
const data = excelData.map(item =&amp;gt; {
  return {
    ...item,
    appDtDesc: changeDateForExcel(item.appDt),
    appTmDesc: changeTimeForExcel(item.appTm),
    ccDtDesc: changeDateForExcel(item.ccDt),
    ccTmDesc: changeTimeForExcel(item.ccTm),
    settlmntDtDesc: changeDateForExcel(item.settlmntDt)
  };
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;컬럼 꾸미기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724291525038&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 컬럼 배경색 설정
const headerFill = {
  type: 'pattern',
  pattern: 'solid',
  fgColor: {argb: '6666ff'},
}
// 컬럼 폰트 설정
const headerFont = {bold: true, color: {argb: 'ffffff'}}

// 모든 컬럼에 적용
for (let i = 1; i &amp;lt;= worksheet.columnCount; i++) {
  const headerEachCell = worksheet.getCell(`${String.fromCharCode(i + 64)}1`);
  headerEachCell.fill = headerFill;
  headerEachCell.font = headerFont;
  headerEachCell.alignment = { horizontal: 'center' };
}&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Reperence&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. ExcelJS 사용법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blckchainetc.tistory.com/entry/Nodejs-Exceljs-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%B4%9D%EC%A0%95%EB%A6%AC-How-to-use-Exceljs-%ED%85%8C%EC%9D%B4%EB%B8%94-%EB%A7%8C%EB%93%A4%EA%B8%B0-insertRows-columns-value-%EB%93%B1&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://blckchainetc.tistory.com/entry/Nodejs-Exceljs-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%B4%9D%EC%A0%95%EB%A6%AC-How-to-use-Exceljs-%ED%85%8C%EC%9D%B4%EB%B8%94-%EB%A7%8C%EB%93%A4%EA%B8%B0-insertRows-columns-value-%EB%93%B1&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. ExcelJS 다운로드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer-talk.tistory.com/328&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer-talk.tistory.com/328&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;</description>
      <category>Front/JavaScript</category>
      <author>sabeom</author>
      <guid isPermaLink="true">https://devbeomstory.tistory.com/164</guid>
      <comments>https://devbeomstory.tistory.com/164#entry164comment</comments>
      <pubDate>Wed, 14 Aug 2024 16:56:10 +0900</pubDate>
    </item>
    <item>
      <title>[RockyLinux] 사설 네트워크 브릿지 구성하기 (사설 IP)</title>
      <link>https://devbeomstory.tistory.com/159</link>
      <description>&lt;h3 style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;네트워크 브릿지&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사설 네트워크 브리지:&lt;/b&gt;&amp;nbsp;사설 네트워크 브리지는 가상 라우터와 같습니다. 자체적으로 사설 IP 주소를 할당하고 DHCP 서버를 생성합니다. 이 네트워크 브리지에 연결된 KVM 가상 머신은 브리지의 DHCP 서버를 통해 IP 주소를 얻습니다. 네트워크 브리지는 NAT(Network Address Translation)를 사용하여 KVM 가상 머신에 대한 인터넷 연결을 제공합니다. 사설 네트워크 브리지에 연결된 KVM 가상 머신은 서로 통신할 수 있습니다. KVM 호스트(가상 머신이 실행 중인 위치)도 가상 머신에 직접 액세스할 수 있습니다. 그러나 가상 머신은 외부 네트워크에서 액세스할 수 없습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;423&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yzoQM/btsHCbdAOv0/swr6x5sM0tVdpXhrUrIIG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yzoQM/btsHCbdAOv0/swr6x5sM0tVdpXhrUrIIG1/img.png&quot; data-alt=&quot;사설 네트워크 브릿지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yzoQM/btsHCbdAOv0/swr6x5sM0tVdpXhrUrIIG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyzoQM%2FbtsHCbdAOv0%2Fswr6x5sM0tVdpXhrUrIIG1%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;601&quot; height=&quot;244&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;423&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사설 네트워크 브릿지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;공용 네트워크 브리지:&lt;/b&gt;&amp;nbsp;공용 네트워크 브리지는 가상 스위치와 같습니다. 하나의 물리적 네트워크 인터페이스를 브리지에 연결할 수 있으며 네트워크 브리지를 사용하는 KVM 가상 머신은 물리적 네트워크 인터페이스가 연결된 라우터에서 실행되는 DHCP 서버를 사용하여 자체적으로 IP 주소를 할당합니다. 공용 네트워크 브리지를 사용하는 경우 연결된 KVM 가상 머신은 물리적 라우터 또는 네트워크 장치에서 IP 주소를 가져옵니다. KVM 가상 머신은 KVM 호스트와 외부 네트워크에서 서로 액세스할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lAxlN/btsHCtkNYv1/5ibOZi03RI5FHPn7w3oFd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lAxlN/btsHCtkNYv1/5ibOZi03RI5FHPn7w3oFd0/img.png&quot; data-alt=&quot;공용 네트워크 브릿지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lAxlN/btsHCtkNYv1/5ibOZi03RI5FHPn7w3oFd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlAxlN%2FbtsHCtkNYv1%2F5ibOZi03RI5FHPn7w3oFd0%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;589&quot; height=&quot;316&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;공용 네트워크 브릿지&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;style5&quot; /&gt;
&lt;h3 style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;KVM으로 사설 네트워크 브릿지 만들기&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;본인 ip 확인하기&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ ip a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;928&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/05AdP/btsHCme0ppd/EugkPdRs7SqVw6TFXbpG9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/05AdP/btsHCme0ppd/EugkPdRs7SqVw6TFXbpG9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/05AdP/btsHCme0ppd/EugkPdRs7SqVw6TFXbpG9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F05AdP%2FbtsHCme0ppd%2FEugkPdRs7SqVw6TFXbpG9K%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;928&quot; height=&quot;342&quot; data-origin-width=&quot;928&quot; data-origin-height=&quot;342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ sudo virsh net-list --all&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;87&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4o2Ie/btsHCmlMoC4/8PB13oHQKFYYQWN2ugp98k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4o2Ie/btsHCmlMoC4/8PB13oHQKFYYQWN2ugp98k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4o2Ie/btsHCmlMoC4/8PB13oHQKFYYQWN2ugp98k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4o2Ie%2FbtsHCmlMoC4%2F8PB13oHQKFYYQWN2ugp98k%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;386&quot; height=&quot;87&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;87&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;Default 네트워크 브릿지 XML구성파일의 기본값 확인하기&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ sudo virsh net-edit default&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;992&quot; data-origin-height=&quot;378&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVrBR6/btsHCppeQX3/eYKsd48w6jx4mkoobwMMhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVrBR6/btsHCppeQX3/eYKsd48w6jx4mkoobwMMhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVrBR6/btsHCppeQX3/eYKsd48w6jx4mkoobwMMhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVrBR6%2FbtsHCppeQX3%2FeYKsd48w6jx4mkoobwMMhk%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;551&quot; height=&quot;210&quot; data-origin-width=&quot;992&quot; data-origin-height=&quot;378&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;사설 네트워크 브릿지 XML 구성파일 생성하기&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ vim private.xml&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;&amp;lt;network&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;name&amp;gt;private&amp;lt;/name&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;forward mode='nat'/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;bridge name='virbr1' stp='on' delay='0'/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;ip address='10.0.0.1' netmask='255.255.255.0'&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;dhcp&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;range start='10.0.0.2' end='10.0.0.254'/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/dhcp&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;/ip&amp;gt;
&amp;lt;/network&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;lt;name&amp;gt; &lt;/span&gt;&lt;br /&gt;네트워크 이름&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;lt;forward mode='nat' /&amp;gt; &lt;/span&gt;&lt;br /&gt;브리지는 KVM 가상머신의 인터넷 연결을 위해 네트워크 주소 변환을 사용합니다.&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;lt;bridge name='virbr1' stp='on' delay='0' /&amp;gt;&lt;/span&gt;&lt;br /&gt;네트워크 브릿지 인터페이스 이름은 virbr1입니다.&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;lt;ip address='10.0.0.1' netmask='255.255.255.0' &amp;gt;&lt;/span&gt;&lt;br /&gt;네트워크 브릿지는 10.0.0.0/24 사설 네트워크 서브넷을 사용하고 브릿지 인터페이스 virbr1에 대해 IP 주소 10.0.0.1을 할당합니다.&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;lt;dhcp&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;range start='10.0.0.2' end='10.0.0.254'&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;lt;/dhcp&amp;gt;&lt;/span&gt;&lt;br /&gt;KVM은 네트워크 브릿지용 DHCP서버를 실행합니다. 이 네트워크 브릿지를 사용하여 가상머신에 IP주소를 제공합니다. KVM 가상머신에는 10.0.0.2부터 10.0.0.254범위 내의 IP주소가 할당됩니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;private.xml 파일을 사용하여 개인 네트워크 브릿지 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ sudo virsh net-define private.xml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;76&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOY7m3/btsHB9fXHaj/Igk8bDTAzejECWYXItS8k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOY7m3/btsHB9fXHaj/Igk8bDTAzejECWYXItS8k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOY7m3/btsHB9fXHaj/Igk8bDTAzejECWYXItS8k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOY7m3%2FbtsHB9fXHaj%2FIgk8bDTAzejECWYXItS8k1%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;446&quot; height=&quot;76&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;76&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;현재 사설 네트워크 브릿지 상태확인하기&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ sudo virsh net-list --all&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;368&quot; data-origin-height=&quot;97&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/db3YO5/btsHAQveK6m/5zege1g4ZK3WHfHNps4OFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/db3YO5/btsHAQveK6m/5zege1g4ZK3WHfHNps4OFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/db3YO5/btsHAQveK6m/5zege1g4ZK3WHfHNps4OFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdb3YO5%2FbtsHAQveK6m%2F5zege1g4ZK3WHfHNps4OFk%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;368&quot; height=&quot;97&quot; data-origin-width=&quot;368&quot; data-origin-height=&quot;97&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;사설 네트워크 브릿지 활성화하기&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ sudo virsh net-start private&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgCDx8/btsHAxQaDzo/4tUlp2a8ETAAOUOmKL77gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgCDx8/btsHAxQaDzo/4tUlp2a8ETAAOUOmKL77gK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgCDx8/btsHAxQaDzo/4tUlp2a8ETAAOUOmKL77gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgCDx8%2FbtsHAxQaDzo%2F4tUlp2a8ETAAOUOmKL77gK%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;404&quot; height=&quot;59&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사설 네트워크 브릿지 활성화 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716537674797&quot; class=&quot;applescript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ sudo virsh net-list --all&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;391&quot; data-origin-height=&quot;104&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmmJ3p/btsHAQhJYZx/dkIX3Nn8AKD9CnAHxoJBok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmmJ3p/btsHAQhJYZx/dkIX3Nn8AKD9CnAHxoJBok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmmJ3p/btsHAQhJYZx/dkIX3Nn8AKD9CnAHxoJBok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmmJ3p%2FbtsHAQhJYZx%2FdkIX3Nn8AKD9CnAHxoJBok%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;391&quot; height=&quot;104&quot; data-origin-width=&quot;391&quot; data-origin-height=&quot;104&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ ip a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;419&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHwTDz/btsHAMzGWOE/ErwnVYDqJHKpLueupKhhPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHwTDz/btsHAMzGWOE/ErwnVYDqJHKpLueupKhhPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHwTDz/btsHAMzGWOE/ErwnVYDqJHKpLueupKhhPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHwTDz%2FbtsHAMzGWOE%2FErwnVYDqJHKpLueupKhhPK%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;774&quot; height=&quot;349&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;419&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;네트워크 브릿지 부팅 시 자동 시작&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ sudo virsh net-autostart private&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;52&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by8WCV/btsHAyO66ON/wnxStQMxmpzzQbzkGcqiFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by8WCV/btsHAyO66ON/wnxStQMxmpzzQbzkGcqiFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by8WCV/btsHAyO66ON/wnxStQMxmpzzQbzkGcqiFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby8WCV%2FbtsHAyO66ON%2FwnxStQMxmpzzQbzkGcqiFk%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;448&quot; height=&quot;52&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;52&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자동시작 활성화 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716538192585&quot; class=&quot;applescript&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo virsh net-list --all&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;127&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l0Bgs/btsHBOi7M8Q/JcZcrVuIu3EViNfvdi1saK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l0Bgs/btsHBOi7M8Q/JcZcrVuIu3EViNfvdi1saK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l0Bgs/btsHBOi7M8Q/JcZcrVuIu3EViNfvdi1saK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl0Bgs%2FbtsHBOi7M8Q%2FJcZcrVuIu3EViNfvdi1saK%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;407&quot; height=&quot;127&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;127&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;KVM HostOS에서 GuestOS(VM) 사설 네트워크 설정&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lTbZi/btsHBtM6Eg9/bXlKo1kwmnSnWBKyPJl2q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lTbZi/btsHBtM6Eg9/bXlKo1kwmnSnWBKyPJl2q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lTbZi/btsHBtM6Eg9/bXlKo1kwmnSnWBKyPJl2q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlTbZi%2FbtsHBtM6Eg9%2FbXlKo1kwmnSnWBKyPJl2q0%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;676&quot; height=&quot;321&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;492&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GuestOS(VM)에서 nmtui로 고정IP 설정하기&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;nmtui로 VM 인터넷 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ nmtui&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dq2kzn/btsHCs7tgiI/S8JcMklyyrYTMxvkoeFiZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dq2kzn/btsHCs7tgiI/S8JcMklyyrYTMxvkoeFiZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dq2kzn/btsHCs7tgiI/S8JcMklyyrYTMxvkoeFiZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdq2kzn%2FbtsHCs7tgiI%2FS8JcMklyyrYTMxvkoeFiZ1%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;510&quot; height=&quot;453&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;544&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ ip a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GDTit/btsHApx8npX/Is8tjZJMTQ3PM8U8uP3rUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GDTit/btsHApx8npX/Is8tjZJMTQ3PM8U8uP3rUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GDTit/btsHApx8npX/Is8tjZJMTQ3PM8U8uP3rUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGDTit%2FbtsHApx8npX%2FIs8tjZJMTQ3PM8U8uP3rUK%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;711&quot; height=&quot;208&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ ping 8.8.8.8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;442&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JDqaJ/btsHAJpnPfa/J9jZBGkfF1QKOf87sS8330/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JDqaJ/btsHAJpnPfa/J9jZBGkfF1QKOf87sS8330/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JDqaJ/btsHAJpnPfa/J9jZBGkfF1QKOf87sS8330/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJDqaJ%2FbtsHAJpnPfa%2FJ9jZBGkfF1QKOf87sS8330%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;442&quot; height=&quot;86&quot; data-origin-width=&quot;442&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;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Reference&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. KVM + QEMU로, 직접 구성한 NAT 네트워크에 연결된 가상머신 생성하기&lt;br /&gt;&lt;a href=&quot;https://blog.naver.com/love_tolty/222650880951&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;https://blog.naver.com/love_tolty/222650880951&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;2. CentOS8 KVM 네트워크 브릿지 인터페이스를 생성하는 방법&lt;br /&gt;&lt;a href=&quot;https://ko.linux-console.net/?p=16671&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;https://ko.linux-console.net/?p=16671&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <author>sabeom</author>
      <guid isPermaLink="true">https://devbeomstory.tistory.com/159</guid>
      <comments>https://devbeomstory.tistory.com/159#entry159comment</comments>
      <pubDate>Fri, 24 May 2024 15:45:36 +0900</pubDate>
    </item>
    <item>
      <title>[MyBatis] Update Join - table끼리 join해서 update 하기</title>
      <link>https://devbeomstory.tistory.com/153</link>
      <description>&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt; 
   &lt;li&gt;java 8&lt;/li&gt; 
   &lt;li&gt;mybatis&lt;/li&gt; 
   &lt;li&gt;postgreSQL&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;&amp;lt;update id=&quot;updateJoinAdjmCompleted&quot; parameterType=&quot;String&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/* SmartroPay.xml updateJoinAdjmCompleted */
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UPDATE tb_mbr_pay SET
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mpay_sadj_id = temp.padj_sadj_id
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;, mpay_sadj_stat = #{mpayAdjmStat}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;, mpay_adjm_dttm = temp.adj_date
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;, mpay_updt_dttm = now()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT a.*, c.adj_date 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM tmp_mpay_adjm a
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LEFT JOIN tb_shp_adjm b
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ON a.padj_sadj_id = b.sadj_id
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LEFT JOIN tb_adjm c
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ON b.sadj_adjm_id = c.adj_id
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;where a.tid not in (select tid from tmp_mpay_adjm where state_cd != '0')
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;) as temp
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE tb_mbr_pay.mpay_id = temp.padj_mpay_id
&amp;lt;/update&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring/Mybatis</category>
      <author>sabeom</author>
      <guid isPermaLink="true">https://devbeomstory.tistory.com/153</guid>
      <comments>https://devbeomstory.tistory.com/153#entry153comment</comments>
      <pubDate>Thu, 2 May 2024 14:32:26 +0900</pubDate>
    </item>
    <item>
      <title>[MyBatis] Insert Join - table끼리 join해서 insert하기</title>
      <link>https://devbeomstory.tistory.com/152</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Insert into + Join 쿼리&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;우선 join은 select용이다.&lt;br&gt;insert문에 join을 결합하여 사용한다는 말은, &lt;b&gt;&lt;span style=&quot;color: #EF6F53;&quot;&gt;join하여 select한 특수한 값을 골라 insert&lt;/span&gt;&lt;/b&gt; 한다는 말과 같다.&lt;br&gt;&amp;nbsp;&lt;br&gt;다음과 같은 상황일때 사용할 수 있다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q. &lt;b&gt;&lt;span style=&quot;color: #EE2323;&quot;&gt;TB1 에는 있고, TB2에는 없는 레코드&lt;/span&gt;&lt;/b&gt;만 &lt;b&gt;&lt;span style=&quot;color: #006DD7;&quot;&gt;TB2에 추가&lt;/span&gt;&lt;/b&gt;하기&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-height=&quot;307&quot; data-origin-width=&quot;589&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;
 &lt;span data-lightbox=&quot;lightbox&quot; data-url=&quot;https://blog.kakaocdn.net/dn/KkPfA/btrm2nNNyOQ/eT6xJnqHhUsyiQQpslDBq1/img.png&quot;&gt;&lt;a class=&quot;preclusion&quot; href=&quot;https://blog.kakaocdn.net/dn/KkPfA/btrm2nNNyOQ/eT6xJnqHhUsyiQQpslDBq1/img.png&quot; data-fslightbox=&quot;gallery&quot;&gt;&lt;img class=&quot;ls-is-cached lazyloaded&quot; src=&quot;https://blog.kakaocdn.net/dn/KkPfA/btrm2nNNyOQ/eT6xJnqHhUsyiQQpslDBq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKkPfA%2Fbtrm2nNNyOQ%2FeT6xJnqHhUsyiQQpslDBq1%2Fimg.png&quot; data-src=&quot;https://blog.kakaocdn.net/dn/KkPfA/btrm2nNNyOQ/eT6xJnqHhUsyiQQpslDBq1/img.png&quot; data-srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKkPfA%2Fbtrm2nNNyOQ%2FeT6xJnqHhUsyiQQpslDBq1%2Fimg.png&quot; data-origin-height=&quot;307&quot; data-origin-width=&quot;589&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;/figure&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;codeBlock_stylish&quot;&gt;
 &lt;span data-ke-language=&quot;sql&quot;&gt;sql&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;codeBlock_stylish&quot;&gt;
 &lt;span data-ke-language=&quot;sql&quot;&gt;&lt;/span&gt; 
 &lt;pre id=&quot;code_1714627292555&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO TB2 (코드, 년도)
(
  SELECT A.코드, A.년도 -- 추가할 필드
  FROM TB1 A LEFT JOIN TB2 B 
  ON A.코드 = B.코드
  WHERE B.코드 IS NULL -- join한 TB2테이블의 필드가 NULL이라는 말은 TB2에는 없는 값을 의미한다.
)&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt; 
   &lt;li&gt;java 8&lt;/li&gt; 
   &lt;li&gt;mybatis&lt;/li&gt; 
   &lt;li&gt;postgreSQL&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;&amp;lt;insert id=&quot;insertPadjData&quot; parameterType=&quot;com.bit.bizportal.common.voCommon.pay.adjm.AdjmDataVO&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/* SmartroPay.xml insertPadjData */
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INSERT INTO tb_mpay_adjm
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padj_mpay_id, padj_sadj_id, padj_reg_dttm, padj_updt_dttm,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tid, otid, app_dt, app_tm, cc_dt,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cc_tm, mid, moid, svc_cd, pin_no,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;goods_nm, amt, tax_amt, tax_free_amt, discount_amt,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pay_amt, coupon_amt, cpx_amt, fn_cpx_amt, green_deposit,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;instmnt_mon, no_int_cl, point_cl, card_cl, bc_card_cl,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;state_cd, general_fee, general_vat, no_int_fee, no_int_vat,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pnt_fee, pnt_vat, ec_fee, ec_vat, auth_fee,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;auth_vat, coupon_fee, coupon_var, cpx_fee, cpx_vat,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;deposit_amt, settlmnt_dt, isu_cd, fn_cd, fn_no,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app_no, ccy_cd, trans_cl
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp.padj_mpay_id, temp.padj_sadj_id, temp.padj_reg_dttm, temp.padj_updt_dttm,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp.tid, temp.otid, temp.app_dt, temp.app_tm, temp.cc_dt,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp.cc_tm, temp.mid, temp.moid, temp.svc_cd, temp.pin_no,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp.goods_nm, temp.amt, temp.tax_amt, temp.tax_free_amt, temp.discount_amt,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp.pay_amt, temp.coupon_amt, temp.cpx_amt, temp.fn_cpx_amt, temp.green_deposit,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp.instmnt_mon, temp.no_int_cl, temp.point_cl, temp.card_cl, temp.bc_card_cl,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp.state_cd, temp.general_fee, temp.general_vat, temp.no_int_fee, temp.no_int_vat,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp.pnt_fee, temp.pnt_vat, temp.ec_fee, temp.ec_vat, temp.auth_fee,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp.auth_vat, temp.coupon_fee, temp.coupon_var, temp.cpx_fee, temp.cpx_vat,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp.deposit_amt, temp.settlmnt_dt, temp.isu_cd, temp.fn_cd, temp.fn_no,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp.app_no, temp.ccy_cd, temp.trans_cl
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM tmp_mpay_adjm temp
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LEFT JOIN tb_mpay_adjm tma
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ON temp.tid = tma.tid and temp.state_cd = tma.state_cd
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE tma.padj_id is null
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;lt;/insert&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot;&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;Reference&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;1. 인파 - insert into join 사용해보기&lt;br&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/MYSQL-&quot; target=&quot;_self&quot;&gt;&lt;span&gt;https://inpa.tistory.com/entry/MYSQL-&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #0070D1;&quot;&gt; -INSERT-INTO-JOIN-사용해보기&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring/Mybatis</category>
      <author>sabeom</author>
      <guid isPermaLink="true">https://devbeomstory.tistory.com/152</guid>
      <comments>https://devbeomstory.tistory.com/152#entry152comment</comments>
      <pubDate>Thu, 2 May 2024 14:22:59 +0900</pubDate>
    </item>
    <item>
      <title>[MyBatis] Batch Insert - 대용량 데이터 insert</title>
      <link>https://devbeomstory.tistory.com/151</link>
      <description>&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;1. &lt;b&gt;SqlSession 의 ExecutorType.BATCH&lt;/b&gt;&lt;br&gt;ExecutorType.BATCH 를 사용하면 바로 DB 로 쿼리를 날리지 않고 쿼리를 미리 쌓아뒀다가 commit 시 connection에 모든 쿼리를 넘겨준다.&lt;br&gt;2. &lt;b&gt;flushStatements&lt;/b&gt;&lt;br&gt;MyBatis에서는 flushStatements라는 설정 옵션을 제공합니다. 이 옵션을 활용하면 일정량의 SQL 문을 배치 처리하고 커밋하기 전에 임시로 버퍼에 저장하는 방식으로 대용량 데이터 처리 작업의 성능을 개선할 수 있습니다. 대용량 데이터 작업을 수행하는 동안 많은 SQL문을 생성하고 실행할 수 있습니다. 이때 flushStatement를 사용하면, 일정한 개수나 시간 간격으로 SQL 문을 배치로 처리하고 커밋하므로 다음과 같은 장점이 있습니다.&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;작업 속도 향상: 일정한 간격마다 SQL문을 배치로 처리하기 때문에 작업이 빨라집니다.&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;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;1. 기본 insert &lt;/b&gt;&lt;/p&gt;&lt;pre class=&quot;dust&quot; style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;code&gt;&amp;lt;!-- 데이터를 한 건씩 Insert 하는 쿼리 --&amp;gt;
&amp;lt;insert id=&quot;insertItem&quot; parameterType=&quot;com.example.batchjob.dto.ItemDto&quot;&amp;gt;
    INSERT INTO item_list
    VALUES ( #{itemCode}, #{name}, #{kindCode}, #{price})
&amp;lt;/insert&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;pre class=&quot;pgsql&quot; style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;code&gt;INSERT INTO item_list
        VALUES ( '0', '0', '0', 0)
 {executed in 6 msec}
INSERT INTO item_list
        VALUES ( '1', '1', '1', 1)
 {executed in 5 msec}
INSERT INTO item_list
        VALUES ( '2', '2', '2', 2)
 {executed in 4 msec}
INSERT INTO item_list
        VALUES ( '3', '3', '3', 3)
 {executed in 4 msec}
INSERT INTO item_list
        VALUES ( '4', '4', '4', 4)
 {executed in 4 msec}&lt;/code&gt;&lt;/pre&gt;&lt;hr 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;2. Mybatis &amp;lt;foreach&amp;gt; 태그사용&lt;/b&gt;&lt;/p&gt;&lt;pre class=&quot;dust&quot; style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;code&gt;&amp;lt;!-- foreach를 이용한 다건의 데이터 Insert --&amp;gt;
&amp;lt;insert id=&quot;insertItemList&quot; parameterType=&quot;com.example.batchjob.dto.ItemDto&quot;&amp;gt;
    INSERT INTO item_list
    VALUES
    &amp;lt;foreach collection=&quot;list&quot; item=&quot;item&quot; open=&quot;(&quot; close=&quot;)&quot; separator=&quot;), (&quot;&amp;gt;
        #{item.itemCode}, #{item.name}, #{item.kindCode}, #{item.price}
    &amp;lt;/foreach&amp;gt;
&amp;lt;/insert&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 insert문으로 다 건의 데이터가 입력된다.&lt;/p&gt;&lt;pre class=&quot;lsl&quot; style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;code&gt;INSERT INTO item_list
    VALUES
        ( '0', '0', '0', 0 )
        , ( '1', '1', '1', 1)
        , ( '2', '2', '2', 2)
        , ( '3', '3', '3', 3)
        , ( '4', '4', '4', 4)
 {executed in 13 msec}&lt;/code&gt;&lt;/pre&gt;&lt;hr 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;3. SqlSession ExcuteType.BATCH 사용&lt;/b&gt;&lt;/p&gt;&lt;pre class=&quot;java&quot; style=&quot;color: #000000; text-align: left;&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// mapper.XML
&amp;lt;!-- 데이터를 한 건씩 Insert 하는 쿼리 --&amp;gt;
&amp;lt;insert id=&quot;insertItem&quot; parameterType=&quot;com.example.batchjob.dto.ItemDto&quot;&amp;gt;
    INSERT INTO item_list
    VALUES ( #{itemCode}, #{name}, #{kindCode}, #{price})
&amp;lt;/insert&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;reasonml&quot; style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;code&gt;@Test
@DisplayName(&quot;SqlSession Execute.BATCH 를 이용한 배치처리&quot;)
void BulkInsertUsingSqlSession() {

    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
    ItemMapper mapper = sqlSession.getMapper(ItemMapper.class);

    for (ItemDto itemDto : inputDataList) {
        retValue = mapper.insertItem(itemDto); // 리턴값으로 row와 상관없는 값이 나옴
    }
    sqlSession.flushStatements();
    sqlSession.Commit()
}&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;sql&quot; style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;code&gt;batching 5 statements:
1:  INSERT INTO item_list#
        VALUES ( '0', '0', '0', 0)
2:  INSERT INTO item_list
        VALUES ( '1', '1', '1', 1)
3:  INSERT INTO item_list
        VALUES ( '2', '2', '2', 2)
4:  INSERT INTO item_list
        VALUES ( '3', '3', '3', 3)
5:  INSERT INTO item_list
        VALUES ( '4', '4', '4', 4)
 {executed in 13 msec}&lt;/code&gt;&lt;/pre&gt;&lt;hr 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;4. 각 방식의 성능비교&lt;/b&gt;&lt;br&gt;sqlSession batch&amp;nbsp; &amp;nbsp;&amp;lt;&amp;nbsp; &amp;nbsp;mybatis &amp;lt;forEach&amp;gt;&amp;nbsp; &amp;nbsp;&amp;lt;&amp;nbsp; &amp;nbsp;기본 insert 순으로 속도가 느려짐&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt; 
   &lt;li&gt;java 8&lt;/li&gt; 
   &lt;li&gt;mybatis&lt;/li&gt; 
   &lt;li&gt;postgreSQL&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;순서&lt;br&gt; 
  &lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt; 
   &lt;li&gt;sqlSession ExecutorType.BATCH 선언&lt;/li&gt; 
   &lt;li&gt;batchMapper 선언&lt;/li&gt; 
   &lt;li&gt;batch insert할 임시테이블 생성 (temporary table)&lt;/li&gt; 
   &lt;li&gt;batch insert 하기 전 가맹점 마다 임시테이블 데이터 모두 삭제 (truncate)&lt;/li&gt; 
   &lt;li&gt;batch insert&lt;/li&gt; 
   &lt;li&gt;batch insert를 한꺼번에 저장시 속도가 떨어지므로 1000건씩 끊어 넣기 (1000건이 퍼포먼스 제일 높게 나옴)&lt;/li&gt; 
   &lt;li&gt;반드시 finally 에 sqlSession을 닫는 기능을 넣어야함. 오류가 나더라도 finally는 실행됌.&lt;/li&gt; 
  &lt;/ol&gt; &lt;/li&gt; 
&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class service {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final SqlSessionFactory sqlSessionFactory;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final PlatformTransactionManager transactionManager;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final SmartroPayRepo smartroPayRepo;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final int BATCH_SIZE = 1000;&amp;nbsp;&amp;nbsp;// batch insert size 1000건씩 끊어 넣기

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Boolean insertAdjmData(AdjmResVO adjmResVO, String payDate) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SmartroPayRepo batchMapper = sqlSession.getMapper(SmartroPayRepo.class);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/* Transaction Start */
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/* 임시테이블 생성 */
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// smartroPayRepo.createTempMpayAdjm();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;batchMapper.createTempMpayAdjm();	// create temporary table
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sqlSession.flushStatements();	// commit
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch (Exception e) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;log.info(&quot;already createTempMpayAdjm On insertAdjmData()&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/* 임시테이블에 있는 데이터 모두 삭제 */
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// sqlSession.update(&quot;com.bit.bizportal.admin.modules.smartroPay.SmartroPayRepo.truncateTempMpayAdjm&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;batchMapper.truncateTempMpayAdjm();	// truncate temporary table

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int batchInsertCount = 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;List&amp;lt;AdjmDataVO&amp;gt; adjmList = batchMapper.selectAdjmList();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (AdjmDataVO adjmDataVO : adjmList) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// sqlSession.insert(&quot;com.bit.bizportal.admin.modules.smartroPay.SmartroPayRepo.insertTempPadjData&quot;, adjmDataVO);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;batchMapper.insertTempPadjData(adjmDataVO);	// batch insert

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/* BATCH_SIZE 만큼 끊어 넣기 (1000건) */
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;batchInsertCount++;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (batchInsertCount % BATCH_SIZE == 0) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sqlSession.flushStatements();	// commit
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;batchInsertCount = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// sqlSession.insert(&quot;com.bit.bizportal.admin.modules.smartroPay.SmartroPayRepo.insertPadjData&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;batchMapper.insertPadjData();	// batch insert
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sqlSession.flushStatements();	// commit
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/* Transaction Commit */
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// transactionManager.commit(status);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/* Transaction Rollback */
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// transactionManager.rollback(status);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} finally {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sqlSession.flushStatements();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sqlSession.close();	// SqlSession 종료
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sqlSession.clearCache();	// SqlSession 리소스 반납
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;mapper.xml&lt;br&gt;insert, update, select 등 기존 방식과 동일하게 사용하면 됌&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// mapper.xml
&amp;lt;!--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;create temporary table, 임시테이블 생성 --&amp;gt;
&amp;lt;update id=&quot;createTempMpayAdjm&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CREATE temp table tmp_mpay_adjm (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padj_id int,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padj_mpay_id int,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padj_sadj_id int,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padj_reg_dttm timestamp,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padj_updt_dttm timestamp,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tid text,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;otid text&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);
&amp;lt;/update&amp;gt;

&amp;lt;!-- truncate table, 테이블 내 모든 데이터 삭제 --&amp;gt;
&amp;lt;update id=&quot;truncateTempMpayAdjm&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TRUNCATE TABLE tmp_mpay_adjm;
&amp;lt;/update&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot;&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;Reference&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;1. mybatis 대량 데이터 INSERT - sqlSessionFactory 이용!&lt;br&gt;&lt;a href=&quot;https://jy-note.tistory.com/26&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://jy-note.tistory.com/26&lt;/span&gt;&lt;/a&gt;&lt;br&gt;2. [bulk insert/update] mybatis 배치작업과 리턴값(returnValue)&lt;br&gt;&lt;a href=&quot;https://velog.io/@aszxvcb/Bulk-InsertUpdate-%EB%B0%B0%EC%B9%98%EC%9E%91%EC%97%85%EC%97%90%EC%84%9C%EC%9D%98-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%B2%98%EB%A6%AC-%EB%A6%AC%ED%84%B4%EA%B0%92returnValue&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://velog.io/@aszxvcb/Bulk-InsertUpdate-%EB%B0%B0%EC%B9%98%EC%9E%91%EC%97%85%EC%97%90%EC%84%9C%EC%9D%98-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%B2%98%EB%A6%AC-%EB%A6%AC%ED%84%B4%EA%B0%92returnValue&lt;/span&gt;&lt;/a&gt;&lt;br&gt;3. myBatis에서 대량의 데이터를 넣을때 bulk insert를 사용하자&lt;br&gt;&lt;a href=&quot;https://javairus.tistory.com/18&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://javairus.tistory.com/18&lt;/span&gt;&lt;/a&gt;&lt;br&gt;4. [Oracle] Spring, Mybatis에서 대량 데이터 INSERT 수행. multirow, 다건 삽입 수행하기&lt;br&gt;&lt;a href=&quot;https://infjin.tistory.com/192&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://infjin.tistory.com/192&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring/Mybatis</category>
      <author>sabeom</author>
      <guid isPermaLink="true">https://devbeomstory.tistory.com/151</guid>
      <comments>https://devbeomstory.tistory.com/151#entry151comment</comments>
      <pubDate>Thu, 2 May 2024 13:59:31 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Enum , Optional 참고자료</title>
      <link>https://devbeomstory.tistory.com/149</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;에러사항.&lt;br&gt;Spring에서 객체 필드데이터가 List일때 Null인지 아닌지 체크가 필요할때 Optional 사용이 불가하다.&lt;br&gt;이럴경우, Optioanl이 아닌 org.springframework.uril 라이브러리에서 제공하는 Objectutils.isEmpty()를 사용하면 null과 빈 배열을 동시에 체크할수 있다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot;&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;Reference&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;1. Enum 사용법 - 응용하기 - 망나니개발자&lt;br&gt;&lt;a href=&quot;https://mangkyu.tistory.com/74&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://mangkyu.tistory.com/74&lt;/span&gt;&lt;/a&gt;&lt;br&gt;2.Java Enum 활용기 - 우아한&lt;br&gt;&lt;a href=&quot;https://techblog.woowahan.com/2527/&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://techblog.woowahan.com/2527/&lt;/span&gt;&lt;/a&gt;&lt;br&gt;3.[Java] 스트림 활용 - anyMatch, noneMatch, findAny, reduce&lt;br&gt;&lt;a href=&quot;https://m.blog.naver.com/adamdoha/222199320102&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://m.blog.naver.com/adamdoha/222199320102&lt;/span&gt;&lt;/a&gt;&lt;br&gt;4.[Java] Optional이란? 개념 및 사용법&lt;br&gt;&lt;a href=&quot;https://mangkyu.tistory.com/70&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://mangkyu.tistory.com/70&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <author>sabeom</author>
      <guid isPermaLink="true">https://devbeomstory.tistory.com/149</guid>
      <comments>https://devbeomstory.tistory.com/149#entry149comment</comments>
      <pubDate>Thu, 28 Mar 2024 17:56:53 +0900</pubDate>
    </item>
    <item>
      <title>[RockyLinux] 윈도우에서 Rocky Linux 원격접속 하기 (원격데스크톱)</title>
      <link>https://devbeomstory.tistory.com/145</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. epel 설치&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ yum install epel-release&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;2. xrdp 및 tigervnc 설치&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ yum install xrdp tigervnc-server

$ rpm -qa |grep tigervnc&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;3. 방화벽 설정 및 재실행&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ firewall-cmd --permanent --zone=public --add-port=3389/tcp

$ firewall-cmd --reload

# 방화벽 확인
$ firewall-cmd --list-ports&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;4. xrdp 서비스 재실행&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ systemctl enable xrdp.service

$ systemctl start xrdp.service

$ systemctl status xrdp.service&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;5. 포트 확인&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ netstat -nap | grep 3389&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;6. window에서 원격 데스크톱 연결&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;username, password에 리눅스계정 입력하기&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8w6oL/btsFuJrQiJ9/Klrf6mtzcYqsce5as2fKX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8w6oL/btsFuJrQiJ9/Klrf6mtzcYqsce5as2fKX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8w6oL/btsFuJrQiJ9/Klrf6mtzcYqsce5as2fKX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8w6oL%2FbtsFuJrQiJ9%2FKlrf6mtzcYqsce5as2fKX0%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;428&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <author>sabeom</author>
      <guid isPermaLink="true">https://devbeomstory.tistory.com/145</guid>
      <comments>https://devbeomstory.tistory.com/145#entry145comment</comments>
      <pubDate>Wed, 6 Mar 2024 14:27:10 +0900</pubDate>
    </item>
    <item>
      <title>[RockyLinux]  Rocky Linux 설치하기</title>
      <link>https://devbeomstory.tistory.com/144</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ISO 다운로드&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://rockylinux.org/ko/download&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://rockylinux.org/ko/download&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;873&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZpRLZ/btsFBddlnHB/kGos9Bz5JQkk2UDJ145qy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZpRLZ/btsFBddlnHB/kGos9Bz5JQkk2UDJ145qy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZpRLZ/btsFBddlnHB/kGos9Bz5JQkk2UDJ145qy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZpRLZ%2FbtsFBddlnHB%2FkGos9Bz5JQkk2UDJ145qy0%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;1349&quot; height=&quot;873&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;873&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Minimal : 간편설치 (옵션 선택폭이 좁음)&lt;br&gt;DVD : 전체설치 (옵션 선택이 많음)&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ISO 부팅 USB 만들기 - Rufus&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://rufus.ie/ko/&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://rufus.ie/ko/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;Rufus 다운로드&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;930&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQ8jwP/btsFA9291On/CVeoIkKb6WodBCSvuL0k30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQ8jwP/btsFA9291On/CVeoIkKb6WodBCSvuL0k30/img.png&quot; data-alt=&quot;rufus download&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQ8jwP/btsFA9291On/CVeoIkKb6WodBCSvuL0k30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQ8jwP%2FbtsFA9291On%2FCVeoIkKb6WodBCSvuL0k30%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;710&quot; height=&quot;437&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;930&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;rufus download&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;Rufus로 부팅 USB 만들기&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;419&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qd4Ie/btsFzdd4Yx9/uZdnov1kKGB2mYtcdEyQfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qd4Ie/btsFzdd4Yx9/uZdnov1kKGB2mYtcdEyQfk/img.png&quot; data-alt=&quot;rufus&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qd4Ie/btsFzdd4Yx9/uZdnov1kKGB2mYtcdEyQfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqd4Ie%2FbtsFzdd4Yx9%2FuZdnov1kKGB2mYtcdEyQfk%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;309&quot; height=&quot;426&quot; data-origin-width=&quot;419&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;rufus&lt;/figcaption&gt;
&lt;/figure&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;Rocky Linux 설치&lt;/b&gt;&lt;/h3&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 설치 전 iso파일 무결성 검사하기&lt;/b&gt;&lt;/h4&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqe19V/btsFzexmGV7/b77fIYH6yIu8ujWYKwEZ8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqe19V/btsFzexmGV7/b77fIYH6yIu8ujWYKwEZ8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqe19V/btsFzexmGV7/b77fIYH6yIu8ujWYKwEZ8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbqe19V%2FbtsFzexmGV7%2Fb77fIYH6yIu8ujWYKwEZ8K%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;677&quot; height=&quot;506&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iso 파일의 무결성을 검사하기 위해 Test this media &amp;amp; install Rocky Linux 선택&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 설치환경 언어 선택하기&lt;/b&gt;&lt;/h4&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NYV4t/btsFyywfqCv/4krXPcsWyxGac03s05uA31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NYV4t/btsFyywfqCv/4krXPcsWyxGac03s05uA31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NYV4t/btsFyywfqCv/4krXPcsWyxGac03s05uA31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNYV4t%2FbtsFyywfqCv%2F4krXPcsWyxGac03s05uA31%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;676&quot; height=&quot;506&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;3. 설치요약&lt;/b&gt;&lt;/h4&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xzihm/btsFAufBnIP/HhuzPzCnbuwrYTu54qIIk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xzihm/btsFAufBnIP/HhuzPzCnbuwrYTu54qIIk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xzihm/btsFAufBnIP/HhuzPzCnbuwrYTu54qIIk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXzihm%2FbtsFAufBnIP%2FHhuzPzCnbuwrYTu54qIIk0%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;675&quot; height=&quot;516&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/ul&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5yNVr/btsFyv7oYy9/MfrWyNHgUbrw3WVnsJkqJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5yNVr/btsFyv7oYy9/MfrWyNHgUbrw3WVnsJkqJK/img.png&quot; data-alt=&quot;사용자정의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5yNVr/btsFyv7oYy9/MfrWyNHgUbrw3WVnsJkqJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5yNVr%2FbtsFyv7oYy9%2FMfrWyNHgUbrw3WVnsJkqJK%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;680&quot; height=&quot;513&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사용자정의&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;507&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CpMk0/btsFB2bNSP8/oskyjZjJvH3L8yo8s957kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CpMk0/btsFB2bNSP8/oskyjZjJvH3L8yo8s957kK/img.png&quot; data-alt=&quot;수동 파티션 설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CpMk0/btsFB2bNSP8/oskyjZjJvH3L8yo8s957kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCpMk0%2FbtsFB2bNSP8%2FoskyjZjJvH3L8yo8s957kK%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;678&quot; height=&quot;507&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;507&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수동 파티션 설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;767&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci4vTu/btsFyxxqX6h/l7xEityi6MsxxDYYtCfSp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci4vTu/btsFyxxqX6h/l7xEityi6MsxxDYYtCfSp0/img.png&quot; data-alt=&quot;설정이 완료됬으면 Accept Changes 클릭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci4vTu/btsFyxxqX6h/l7xEityi6MsxxDYYtCfSp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci4vTu%2FbtsFyxxqX6h%2Fl7xEityi6MsxxDYYtCfSp0%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;767&quot; height=&quot;576&quot; data-origin-width=&quot;767&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;설정이 완료됬으면 Accept Changes 클릭&lt;/figcaption&gt;
&lt;/figure&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;/ul&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;503&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d25GUC/btsFsZVVsX8/JhkKTxpid8C7pixLK1Jt91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d25GUC/btsFsZVVsX8/JhkKTxpid8C7pixLK1Jt91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d25GUC/btsFsZVVsX8/JhkKTxpid8C7pixLK1Jt91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd25GUC%2FbtsFsZVVsX8%2FJhkKTxpid8C7pixLK1Jt91%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;680&quot; height=&quot;503&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;503&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci0zKD/btsFB2pl6YH/kugUEaKrci0WpcU2DkmHE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci0zKD/btsFB2pl6YH/kugUEaKrci0WpcU2DkmHE1/img.png&quot; data-alt=&quot;설치완료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci0zKD/btsFB2pl6YH/kugUEaKrci0WpcU2DkmHE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci0zKD%2FbtsFB2pl6YH%2FkugUEaKrci0WpcU2DkmHE1%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;508&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;설치완료&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <author>sabeom</author>
      <guid isPermaLink="true">https://devbeomstory.tistory.com/144</guid>
      <comments>https://devbeomstory.tistory.com/144#entry144comment</comments>
      <pubDate>Wed, 6 Mar 2024 14:16:54 +0900</pubDate>
    </item>
  </channel>
</rss>