<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자로 살아남기</title>
    <link>https://dev-tak.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 6 Jul 2026 20:58:06 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>devTak</managingEditor>
    <image>
      <title>개발자로 살아남기</title>
      <url>https://tistory1.daumcdn.net/tistory/4039183/attach/51eb23ef22bf49c18e897132f65917f8</url>
      <link>https://dev-tak.tistory.com</link>
    </image>
    <item>
      <title>Monolithic Module Architecture</title>
      <link>https://dev-tak.tistory.com/22</link>
      <description>&lt;h1 data-pm-slice=&quot;1 2 []&quot;&gt;Module 관리&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈도 하나의 프로젝트처럼 생겼는데, 어떻게 관리하는게 좋을까?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-pm-slice=&quot;1 2 []&quot; data-ke-size=&quot;size26&quot;&gt;SubModule 로의 관리?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서브모듈이란,&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Git 저장소 안에 다른 Git 저장소를 디렉토리로 분리해 넣는 것이 서브모듈이다. 다른 독립된 Git 저장소를 Clone 해서 내 Git 저장소 안에 포함할 수 있으며 각 저장소의 커밋은 독립적으로 관리한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;807&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1r1MU/btsPpXMNLyA/OtPrRe9hFOz6aSME5XPAlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1r1MU/btsPpXMNLyA/OtPrRe9hFOz6aSME5XPAlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1r1MU/btsPpXMNLyA/OtPrRe9hFOz6aSME5XPAlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1r1MU%2FbtsPpXMNLyA%2FOtPrRe9hFOz6aSME5XPAlk%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;807&quot; height=&quot;495&quot; data-origin-width=&quot;807&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size23&quot;&gt;API 프로젝트를 SubModule 로 구성하는것에 대한 장점?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MSA 구성에 앞서 프로젝트 레포지토리를 분리하는것&lt;/li&gt;
&lt;li&gt;각 프로젝트별 강제적인 분리를 보다 직관적으로 표현&lt;/li&gt;
&lt;li&gt;각 도메인(모듈)별 별도의 CI/CD 구성과 커밋을 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size23&quot;&gt;API 프로젝트를 SubModule 로 구성하는것에 대한 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MSA 구성에 앞서 프로젝트 레포지토리를 미리 분리하는것이 맞는 판단인가?&lt;/li&gt;
&lt;li&gt;각 프로젝트별 강제적인 분리를 직관적으로 하는것이 트러블슈팅 / 유지보수등 운영에 용이한가?&lt;/li&gt;
&lt;li&gt;각 도메인(모듈)별 별도의 CI/CD 구성과 커밋을 관리하는 것이 모놀리식 방식에 맞는것인가?&lt;/li&gt;
&lt;li&gt;SubModule 을 구성함으로써 CI/CD 스크립트 작성 및 구성에 리소스가 들어가게 된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그렇다고 MSA 로 분리하였을 때, CI/CD 구성을 변경하지 않아도 되는가? NO!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;각각의 모듈들이 MSA 구성이 아닌 환경에서 독립적으로 사용이 불가능하다.&lt;/li&gt;
&lt;li&gt;모듈별 의존성이 있는 기능에 대해 배포를 다수 처리&lt;/li&gt;
&lt;li&gt;각각의 모듈별로 존재할 때, 특정 모듈만 빌드하는것이 불가능&lt;/li&gt;
&lt;li&gt;각 모듈별 시멘틱버저닝에 대한 각 모듈별 체킹이 필수적으로 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #e00000;&quot;&gt;&lt;b&gt;SubModule 방식은 적합하지 않음&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h1 data-pm-slice=&quot;1 1 []&quot;&gt;무엇이 하고싶은가?&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 모듈별 의존성을 최소화하여 MSA 구성 시, 빠르게 구성할 수 있도록 하는 것&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;모놀리식 아키텍쳐에서 어떻게 의존성을 최소화 할 수 있는가?&lt;/h2&gt;
&lt;h1 data-pm-slice=&quot;1 1 []&quot;&gt;1. Adapter Pattern&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wlhSA/btsPpUieJRZ/Fsn6FlKASkPV0k3XgT9s2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wlhSA/btsPpUieJRZ/Fsn6FlKASkPV0k3XgT9s2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wlhSA/btsPpUieJRZ/Fsn6FlKASkPV0k3XgT9s2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwlhSA%2FbtsPpUieJRZ%2FFsn6FlKASkPV0k3XgT9s2K%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;832&quot; height=&quot;393&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;Interface&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;export interface ProductService {
  getProduct(input: getProductDto): Promise&amp;lt;ProductResponse&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Adapter (Internal)&lt;/h2&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;@Injectable()
export class LocalProductServiceImpl implements ProductService {
  constructor(private readonly repo: ProductRepository) {}

  async getProduct(input: getProductDto): Promise&amp;lt;ProductResponse&amp;gt; {
    // 내부 도메인 로직 실행
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Adapter (gRPC)&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Injectable()
export class GrpcProductServiceImpl implements ProductService {
  constructor(@Inject(GRPC_CLIENT) private client: ProductGrpcClient) {}

  async getProduct(input: getProductDto): Promise&amp;lt;ProductResponse&amp;gt; {
    return this.client.getProduct(input); // gRPC 호출
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;헥사고날아키텍쳐(포트앤 어댑터)에서 영감을 받음&lt;/h3&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;주문 모듈 구현체 provider 등록&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;// order/order.module.ts
@Module({
  providers: [
    {
      provide: ProductService,
      useClass: LocalProductServiceImpl, // 해당영역 gRPC로 수정
    },
  ],
  exports: [OrderService],
})
export class OrderModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로젝트 디렉토리 구성안&lt;/h2&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;src/
├── order/
│   ├── application/
│   │   └── order.service.ts
│   ├── domain/
│   └── order.module.ts
│
├── member/
│   ├── application/
│   │   └── member.service.ts
│   └── member.module.ts
│
├── shared/
│   ├── adapters/
│   │   ├── member/
│   │   │   ├── grpc-member.service.ts
│   │   │   └── local-member.service.ts
│   │   └── order/
│   │       ├── grpc-order.service.ts
│   │       └── local-order.service.ts
│   ├── interfaces/
│   │   ├── member.service.interface.ts
│   │   └── order.service.interface.ts
│   └── domain/
│       └── proto/
│           └── order.proto&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Member Module&lt;/h3&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;// src/member/member.module.ts
import { Module } from '@nestjs/common';
import { MemberService } from './application/member.service';
import { OrderService } from '../shared/interfaces/order.service.interface';
import { LocalOrderService } from '../shared/adapters/order/local-order.service';
// import { GrpcOrderService } from '../shared/adapters/order/grpc-order.service';
import { OrderModule } from '../order/order.module';

@Module({
  imports: [OrderModule],
  providers: [
    MemberService,
    {
      provide: OrderService,
      useClass: process.env.USE_GRPC === 'true' ? GrpcOrderService : LocalOrderService,
    },
  ],
})
export class MemberModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;여기까지는 괜찮을 수 있는데, MSA 로 분리하게 된다면 어떻게 될까&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Order Service MSA 분리&lt;/h3&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;order-service/
├── src/
│   ├── order/
│   │   ├── order.controller.ts
│   │   ├── order.service.ts
│   │   └── ...
│   └── member/
│       ├── grpc-member.service.ts    ✅
│       └── member.service.interface.ts
├── proto/
│   └── member.proto                  ✅
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;???? 이건 아닌 것 같다..&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-pm-slice=&quot;3 1 []&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;공통 gRPC client SDK를 만들어 npm 패키지화..?&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;order-service/
├── package.json  // depends on: &quot;@company/member-client&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대안이 될 수는 있고, 공통 로직을 SDK 화 함으로써, 각 MSA 서비스들이 불필요한 코드를 작성하지 않아도 되는 장점이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 MSA 구성을 준비할 때에도 각각의 서비스별 gRPC Client 는 어찌됐던 중복되기 마련이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그럼.. 이렇게 진행하는 것이 맞을까?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론 : MSA 분리를 위해 모놀리틱서비스의 장점을 해치고, 코드 복잡도가 지나치게 높아진다.&lt;/h3&gt;
&lt;h1 data-pm-slice=&quot;1 3 []&quot;&gt;NestJS 에서 제공하는 Resource 구조로 구현&lt;/h1&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { TestCommerceService } from './test-commerce.service';
import { TestCommerceController } from './test-commerce.controller';

@Module({
  controllers: [TestCommerceController],
  providers: [TestCommerceService], // 각 타 모듈 서비스 주입
})
export class TestCommerceModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;순환참조&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nestjs.com/fundamentals/circular-dependency&quot;&gt;https://docs.nestjs.com/fundamentals/circular-dependency&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;선택적 SDK 구성&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MSA 구성을 대비해 각 서비스 모듈 별 공통 처리를 위한 패키지는 SDK로 관리한다.&lt;/li&gt;
&lt;li&gt;EX ) HttpClient, Redis Connector, 등&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Architecture</category>
      <category>API</category>
      <category>Architecture</category>
      <category>monolithic</category>
      <category>MSA</category>
      <category>nestjs</category>
      <author>devTak</author>
      <guid isPermaLink="true">https://dev-tak.tistory.com/22</guid>
      <comments>https://dev-tak.tistory.com/22#entry22comment</comments>
      <pubDate>Fri, 18 Jul 2025 17:14:18 +0900</pubDate>
    </item>
    <item>
      <title>Langchain 과 Few-Shot 프롬프트 엔지니어링 (feat. OpenAI)</title>
      <link>https://dev-tak.tistory.com/20</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;469&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5slV1/btsIQnSsgHL/25kC9atuym1K4okXLxsBW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5slV1/btsIQnSsgHL/25kC9atuym1K4okXLxsBW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5slV1/btsIQnSsgHL/25kC9atuym1K4okXLxsBW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5slV1%2FbtsIQnSsgHL%2F25kC9atuym1K4okXLxsBW0%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;753&quot; height=&quot;469&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;469&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;FewShow(퓨샷) 프롬프트 엔지니어링이란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LLM 모델에 원하는 예제를 제공하는 프롬프트 엔지니어링 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;종류&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제로 샷(0 Shot) : LLM 모델에게 예제를 제공하지 않는 방식&lt;/li&gt;
&lt;li&gt;원 샷(1 Shot) : LLM 모델에게 한개의 예제를 제공하는 방식&lt;/li&gt;
&lt;li&gt;퓨 샷(Few Shot) : LLM 모델에게 2개 이상의 예제를 제공하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;RAG(Retrieval-Augmented Generation) 와의 차이점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RAG 는 LLM 모델에게 질의할 일종의 템플릿(가이드북)을 제공하는 형태로, RAG 데이터를 우선시하여, 질의에 대한 답변을 진행하는 방식&lt;/li&gt;
&lt;li&gt;RAG 데이터와 달리, FewShot 은, 응답 데이터에 대한 Example 을 제공함으로써, 데이터 규격 형태의 대한 처리에 도움을 주는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Fewshot 은 다양한 예시를 전달하는 방법이지만, 그 한계가 있기 때문에 정확한 예시가 아니라면 만족할만한 응답값을 기대하기 어렵다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예제코드&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Example 데이터 준비&lt;/h3&gt;
&lt;pre id=&quot;code_1722231983862&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain_community.vectorstores import  Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import OpenAI

import sys
sys.path.append('/Users/jinwook/Documents/langchain/quick_start/')
from langchain_const import *

# 유저 인풋 값
user_input_text = &quot;재료: 닭, 토마토, 우유, 밀가루, 팔각&quot;

# 예제
examples = [
  {
    &quot;input&quot;: &quot;재료: 닭고기, 소금, 후추, 마늘&quot;,
    &quot;output&quot;: &quot;진욱 AI가 알려주는 레시피!!: 닭고기를 작은 조각으로 자릅니다. 소금과 후추로 간을 하고, 팬에 기름을 둘러 마늘을 볶습니다.마늘이 노릇해 지면 닭고기를 넣고 익을 때까지 볶습니다. 완성된 닭고기를 접시에 담아 냅니다.&quot;
  },
  {
    &quot;input&quot;: &quot;재료: 쌀, 당근&quot;,
    &quot;output&quot;:&quot;진욱 AI가 알려주는 레시피!!: 쌀을 불려서, 당근이랑 같이 볶아요&quot;
  },
  {
    &quot;input&quot;: &quot;재료: 소고기, 토마토, 당근, 소금, 후추, 고추가루&quot;,
    &quot;output&quot;:&quot;진욱 AI가 알려주는 레시피!!: 소고기를 망치로 두드린다음, 얇게 펴서 후추를 뿌리고, 당근과 토마토를 다져서 고추가루와 함께 볶아요&quot;
  },
  {
    &quot;input&quot;: &quot;재료: 레몬, 바닐라, 밀가루&quot;,
    &quot;output&quot;:&quot;진욱 AI가 알려주는 레시피!!: 밀가루를 반죽해서 빵으로 만든 다음, 레몬과 바닐라를 넣고 오븐에 구우면 완벽&quot;
  },
  {
    &quot;input&quot;: &quot;재료: 닭고기, 파, 양파, 대추, 감자, 한약재&quot;,
    &quot;output&quot;:&quot;진욱 AI가 알려주는 레시피!!: 닭고기를 한번 물에 데친다음, 파, 양파를 반으로 잘라서 준비하고, 대추랑 감자를 넣고 푹 삶아주세요&quot;
  },
]&lt;/code&gt;&lt;/pre&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;/h3&gt;
&lt;pre id=&quot;code_1722232035888&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain_community.vectorstores import  Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import OpenAI

import sys
sys.path.append('/Users/jinwook/Documents/langchain/quick_start/')
from langchain_const import *

# 예제 임베딩
example_selector = SemanticSimilarityExampleSelector.from_examples(
    # 선택한 example들 설정
    examples,
    # 유사한 임베딩값을 찾기 위한 임베딩 모델 설정
    OpenAIEmbeddings(openai_api_key=OPENAI_KEY),
    # vector store 설정
    Chroma,
    # 몇개의 가장 유사한 embedding을 찾을 것인지를 설정
    k=2
)

# 예제 연관성 조회
selected_examples = example_selector.select_examples({&quot;input&quot;: user_input_text})

# 프롬프트 생성
example_prompt = PromptTemplate(
    input_variables=[&quot;input&quot;, &quot;output&quot;], 
    template=&quot;Input: {input}\nOutput: {output}&quot;
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;임베딩된 예제 fewshot Template 생성&lt;/h3&gt;
&lt;pre id=&quot;code_1722232065118&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain_community.vectorstores import  Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import OpenAI

import sys
sys.path.append('/Users/jinwook/Documents/langchain/quick_start/')
from langchain_const import *

# Few Shot 프롬프트 구성
prompt = FewShotPromptTemplate(
    examples=selected_examples, 
    example_prompt=example_prompt,
    suffix=&quot;Input : {input}&quot;,
    input_variables=[&quot;input&quot;],
)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LLM 질의&lt;/h3&gt;
&lt;pre id=&quot;code_1722232089537&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain_community.vectorstores import  Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import OpenAI

import sys
sys.path.append('/Users/jinwook/Documents/langchain/quick_start/')
from langchain_const import *

llm = OpenAI(api_key=OPENAI_KEY)

# Output Parser
parser = StrOutputParser()

# Chaining
chain = prompt | llm | parser

print(chain.invoke({&quot;input&quot;: user_input_text}))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>R&amp;amp;D</category>
      <category>ai</category>
      <category>ai예제</category>
      <category>fewshot</category>
      <category>LangChain</category>
      <category>llm</category>
      <category>openAI</category>
      <category>임베딩</category>
      <category>프롬프트</category>
      <category>프롬프트엔지니어링</category>
      <author>devTak</author>
      <guid isPermaLink="true">https://dev-tak.tistory.com/20</guid>
      <comments>https://dev-tak.tistory.com/20#entry20comment</comments>
      <pubDate>Mon, 29 Jul 2024 14:50:48 +0900</pubDate>
    </item>
    <item>
      <title>Langchain 과 OpenAI 를 이용한 데이터 임베딩과 RAG(Retrieval-Augmented Generation)</title>
      <link>https://dev-tak.tistory.com/19</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;469&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KttzX/btsIor8tED7/zTTKf5lTFkky5ktIEnoPSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KttzX/btsIor8tED7/zTTKf5lTFkky5ktIEnoPSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KttzX/btsIor8tED7/zTTKf5lTFkky5ktIEnoPSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKttzX%2FbtsIor8tED7%2FzTTKf5lTFkky5ktIEnoPSk%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;1009&quot; height=&quot;629&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;469&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;h2 data-ke-size=&quot;size26&quot;&gt;임베딩이란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자연어처리에서 &lt;span style=&quot;background-color: #f3c000;&quot;&gt;사람이 쓰는 자연어를 기계가 이해할 수 있도록 숫자형태인 Vector로 바꾸는 과정&lt;/span&gt; 혹은 일련의 전체 과정을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;One-Hot Enconding&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단어 집합의 크기를 벡터의 차원으로 하고, 표현하고 싶은 단어의 인덱스에 1의 값을 부여하고, 다른 인덱스에는 0을 부여하는 단어의 벡터 표현 방식이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 95.4652%; height: 100px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.1346%; height: 20px;&quot;&gt;아이폰&lt;/td&gt;
&lt;td style=&quot;width: 13.7889%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.7022%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.8628%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.8002%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 10.7648%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.1346%; height: 20px;&quot;&gt;갤럭시&lt;/td&gt;
&lt;td style=&quot;width: 13.7889%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 14.7022%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.8628%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.8002%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 10.7648%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.1346%; height: 20px;&quot;&gt;애플워치&lt;/td&gt;
&lt;td style=&quot;width: 13.7889%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 14.7022%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.8628%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.8002%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 10.7648%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.1346%; height: 20px;&quot;&gt;맥북&lt;/td&gt;
&lt;td style=&quot;width: 13.7889%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 14.7022%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.8628%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.8002%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 10.7648%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.1346%; height: 20px;&quot;&gt;갤럭시북&lt;/td&gt;
&lt;td style=&quot;width: 13.7889%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 14.7022%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.8628%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.8002%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 10.7648%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위와같은 형태의 벡터 데이터를 가질 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;One-Hot Encoding 의 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위와 같은 벡터데이터에는 각 데이터의 크기와 상관없이 데이터 할당량 자체가 특정 사이즈로 고정되어있어 데이터크기 측면에서 불리한 점이 있다. &lt;span style=&quot;background-color: #f3c000;&quot;&gt;희소 벡터(Sparse vector)가 생긴다는 문제&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;단어의 개수가 늘어나면 벡터의 차원이 한없이 커진다는 단점을 가지고 있다.&lt;/li&gt;
&lt;li&gt;단순히 0, 1 의 조합으로 단어를 벡터로 표현이 되었기 때문에 각 단어간 유사성을 판단할 근거가 없다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 위 표와 같이 아이폰, 애플워치, 맥북은 애플제품으로써 유사성을 가지고 갤럭시와 갤럭시북은 삼성제품으로써 유사성을 가지지만 0,1 만으로 데이터 유사성을 판단할 수 없는 단점이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Data Embedding&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1032&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5tIug/btsInOwxOgk/dsWg7rZnlIaEqt5LS3FBvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5tIug/btsInOwxOgk/dsWg7rZnlIaEqt5LS3FBvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5tIug/btsInOwxOgk/dsWg7rZnlIaEqt5LS3FBvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5tIug%2FbtsInOwxOgk%2FdsWg7rZnlIaEqt5LS3FBvK%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;1032&quot; height=&quot;309&quot; data-origin-width=&quot;1032&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 임베딩 처리는 기존 One-hot 인코딩 방식의 단점을 보완하는 벡터표현방식&lt;/li&gt;
&lt;li&gt;0,1 로만 구성되어있는 벡터를 다양한 데이터벡터로 상대적으로 ont-hot 인코딩보다 저차원의 형태로 데이터를 구성&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;957&quot; data-origin-height=&quot;623&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csX7Im/btsIo63DMej/vyNvsFTQbTMg91xtNhBkGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csX7Im/btsIo63DMej/vyNvsFTQbTMg91xtNhBkGk/img.png&quot; data-alt=&quot;2차원 그래프에서 연관성을 표현&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csX7Im/btsIo63DMej/vyNvsFTQbTMg91xtNhBkGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsX7Im%2FbtsIo63DMej%2FvyNvsFTQbTMg91xtNhBkGk%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;743&quot; height=&quot;484&quot; data-origin-width=&quot;957&quot; data-origin-height=&quot;623&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2차원 그래프에서 연관성을 표현&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2차원의 형태에서도 유사성 체크가 가능하나, 데이터양이 많아질 수록 더 정교한 유사성을 비교하기위해 N차원의 데이터 형태로 구성&lt;/li&gt;
&lt;li&gt;one-hot 인코딩과는 다르게 더 적은 차원으로 데이터를 구성할 수 있기 때문에 데이터의 밀집도가 향상되고 &lt;span style=&quot;background-color: #f3c000;&quot;&gt;더 빽빽한 데이터 형태&lt;/span&gt;(Dense Representation)로 구성&lt;/li&gt;
&lt;li&gt;데이터 임베딩 모델
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Word2vec(by Google), FastText(by Facebook), BERT(by Google)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;RAG (Retrieval-Augmented Generation) 처리 과정&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1005&quot; data-origin-height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmJZQS/btsIoQUgcns/12bFDPkTXZJ05L4niHavl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmJZQS/btsIoQUgcns/12bFDPkTXZJ05L4niHavl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmJZQS/btsIoQUgcns/12bFDPkTXZJ05L4niHavl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmJZQS%2FbtsIoQUgcns%2F12bFDPkTXZJ05L4niHavl0%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;1005&quot; height=&quot;345&quot; data-origin-width=&quot;1005&quot; data-origin-height=&quot;345&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Source 및 Load 단계&lt;/b&gt; : 원천이되는 데이터 소스를 가져오거나 주입한다.&amp;nbsp;&lt;/h4&gt;
&lt;pre id=&quot;code_1720139776113&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader(&quot;https://snuac.snu.ac.kr/2015_snuac/wp-content/uploads/2015/07/asiabrief_3-26.pdf&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Transform 단계&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;span&gt; 로드한 데이터를 특정 기준에 맞게 Splitter 를 통한 Transform 을 진행한다&lt;/span&gt;.&amp;nbsp;&lt;/h4&gt;
&lt;pre id=&quot;code_1720139905578&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain.text_splitter import RecursiveCharacterTextSplitter
textSplitter = RecursiveCharacterTextSplitter(chunk_size=50, chunk_overlap=0)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Embed 단계&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;span&gt;&lt;span&gt; Splitter 로 쪼갠 데이터를 위에서 설명한 데이터 임베딩 처리&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1720141976926&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_openai import OpenAIEmbeddings

embeddingsModel = OpenAIEmbeddings(openai_api_key=OPENAI_KEY)
embeddings = embeddingsModel.embed_documents(documents)

print(embeddings[0])

# output
[-0.00743497050557687,
 -0.01563150953761078,
 0.0015626668057332756,
 -0.019168283291034625,
 -0.018213096531648893,
 0.014663413716354573,
 -0.008596684559761767,
 0.004595224625870433,
 -0.005343885021779546,
 -0.0034141486086942847,
 0.011862392228291914,....]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;임베딩 쿼리 질의&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1720142148518&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_openai import OpenAIEmbeddings

embeddings_model = OpenAIEmbeddings(openai_api_key=OPENAI_KEY)
embeddings_query = embeddings_model.embed_query(&quot;안녕!&quot;)

print(len(embeddings_query))
print(embedded_query[:5])

#output
1536
[-0.00743497050557687, -0.01563150953761078, 0.0015626668057332756, -0.019168283291034625, -0.018213096531648893]&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Store 단계&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Embedding 한 데이터를 벡터스토어에 저장&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1720142310654&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sample_texts = [
    &quot;안녕!&quot;,
    &quot;빨간색 공&quot;,
    &quot;파란색 공&quot;,
    &quot;붉은색 공&quot;,
    &quot;푸른색 공&quot;,
]

documents = []
for item in range(len(sample_texts)):
    page = Document(page_content=sample_texts[item])
    documents.append(page)

db = Chroma.from_documents(documents=documents, embedding=embeddings_model)

query = &quot;레드&quot;
docs = db.similarity_search(query)
print(docs[0].page_content)

# output : 빨간색 공

query = &quot;인사&quot;
docs = db.similarity_search(query)
print(docs[0].page_content)

# output : 안녕!&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Retrieve 단계&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; VectorStores 에 저장된 Embedding 데이터를 Prompt 에 추가하여 AI 질의&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1720142433997&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
sys.path.append('/Users/jinwook/Documents/langchain/quick_start/')
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from chat_pdf_template import *
from langchain_openai import ChatOpenAI
from langchain.schema.runnable import RunnablePassthrough

from langchain_const import *

loader = PyPDFLoader(&quot;https://snuac.snu.ac.kr/2015_snuac/wp-content/uploads/2015/07/asiabrief_3-26.pdf&quot;)

# PDF 를 로드하고 일정 기준으로 스플릿한다.
pages = loader.load_and_split()

# 스플릿한 데이터를 추가적으로 스플릿한다.
text_splitter = RecursiveCharacterTextSplitter(chunk_size=50, chunk_overlap=0)
splits = text_splitter.split_documents(pages)

# 임베딩을 통한 벡터데이터 저장
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings(openai_api_key=OPENAI_KEY)) # text-embedding-ada-002
retriever = vectorstore.as_retriever()

llmChatOpenAi = ChatOpenAI(model_name=GPT_MODEL, temperature=0, api_key=OPENAI_KEY)

# RunnablePassThrough 공부하기
ragChain = {&quot;ragContext&quot;: retriever, &quot;question&quot;: RunnablePassthrough()} | ragPromptCustom | llmChatOpenAi

print(ragChain.invoke('한국의 저출산 원인이 뭐야?'))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>R&amp;amp;D</category>
      <category>ai</category>
      <category>bert</category>
      <category>data embedding</category>
      <category>dense</category>
      <category>fastText</category>
      <category>One-Hot</category>
      <category>openai embedding</category>
      <category>sparse</category>
      <category>vectorstore</category>
      <category>Word2Vec</category>
      <author>devTak</author>
      <guid isPermaLink="true">https://dev-tak.tistory.com/19</guid>
      <comments>https://dev-tak.tistory.com/19#entry19comment</comments>
      <pubDate>Fri, 5 Jul 2024 10:23:56 +0900</pubDate>
    </item>
    <item>
      <title>docker-compose 로컬 PHP 개발 환경 구성하기</title>
      <link>https://dev-tak.tistory.com/18</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1460&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C346Z/btsHAsHNwVD/5UgwriloUcfgTwanSqRGq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C346Z/btsHAsHNwVD/5UgwriloUcfgTwanSqRGq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C346Z/btsHAsHNwVD/5UgwriloUcfgTwanSqRGq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC346Z%2FbtsHAsHNwVD%2F5UgwriloUcfgTwanSqRGq0%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;1460&quot; height=&quot;399&quot; data-origin-width=&quot;1460&quot; data-origin-height=&quot;399&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시스템 구성도&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WBqIU/btsHz6rH9ti/eB3jM44TliwBCYT85TeCG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WBqIU/btsHz6rH9ti/eB3jM44TliwBCYT85TeCG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WBqIU/btsHz6rH9ti/eB3jM44TliwBCYT85TeCG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWBqIU%2FbtsHz6rH9ti%2FeB3jM44TliwBCYT85TeCG0%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;737&quot; height=&quot;732&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GIT Branch 관리 및 개발 편의성을 위해 실제 개발 프로젝트는 윈도우 로컬환경에 구성해둔다.&lt;/li&gt;
&lt;li&gt;Docker Container 와 개발 프로젝트의 Volume 를 mount 하여 관리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Docker-compose 파일 관리&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Compose.yml&lt;/h4&gt;
&lt;pre id=&quot;code_1716530531183&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: '3.8'
services:
  php:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: my-laravel-app
    working_dir: /var/www
    volumes:
      - C:\project\laravelProject:/var/www #마운트
    networks:
      - laravel-network
  nginx:
    image: nginx:alpine
    container_name: my-laravel-nginx
    ports:
      - &quot;80:80&quot;
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
      - C:\project\laravelProject:/var/www #마운트
    networks:
      - laravel-network
    depends_on:
      - php
    extra_hosts:
      - &quot;test.co.kr:100.000.00.000&quot; #필요한 호스트 등록
  mariadb:
    image: mariadb:10.4.21
    container_name: my-laravel-mariadb
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_USER: laraveluser
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: secret
    volumes:
      - dbdata:/var/lib/mysql
    ports:
      - &quot;3306:3306&quot;
    networks:
      - laravel-network
  redis:
    image: redis:alpine
    container_name: my-laravel-redis
    ports:
      - &quot;6379:6379&quot;  # 호스트의 포트 3306을 컨테이너의 포트 3306에 매핑합니다.
    networks:
      - laravel-network
networks:
  laravel-network:
volumes:
  dbdata:&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템 구성도에서의 mount 는 php 와 nginx service 영역의 volume 을 통해 마운트를 진행한다.&lt;/li&gt;
&lt;li&gt;hosts 등록이 필요한 경우 nginx service 영역에 extra_hosts 로 등록한다.&lt;/li&gt;
&lt;li&gt;포트 지정은 각 service 별로 ports 로 구성한다.&lt;/li&gt;
&lt;li&gt;네트워크 구성은 각 형태에 따라 구성한다. (networks)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;PHP Dockerfile&lt;/h4&gt;
&lt;pre id=&quot;code_1716530648105&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM php:7.4-fpm
# Install system dependencies
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    build-essential \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    locales \
    zip \
    jpegoptim optipng pngquant gifsicle \
    vim \
    unzip \
    git \
    curl
# Install PHP extensions
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    libonig-dev \
    build-essential \
    &amp;amp;&amp;amp; apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    &amp;amp;&amp;amp; apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    locales \
    zip \
    jpegoptim \
    optipng \
    pngquant \
    gifsicle \
    &amp;amp;&amp;amp; apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    vim \
    git \
    curl \
    &amp;amp;&amp;amp; apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
RUN apt-get update &amp;amp;&amp;amp; docker-php-ext-install \
        mbstring \
    &amp;amp;&amp;amp; docker-php-ext-enable \
        mbstring
RUN apt-get update &amp;amp;&amp;amp; docker-php-ext-install \
        exif \
    &amp;amp;&amp;amp; docker-php-ext-enable \
        exif
RUN apt-get update &amp;amp;&amp;amp; docker-php-ext-install \
        pcntl \
    &amp;amp;&amp;amp; docker-php-ext-enable \
        pcntl
RUN apt-get update &amp;amp;&amp;amp; docker-php-ext-install \
        bcmath \
    &amp;amp;&amp;amp; docker-php-ext-enable \
        bcmath
RUN apt-get update &amp;amp;&amp;amp; docker-php-ext-install \
        gd \
    &amp;amp;&amp;amp; docker-php-ext-enable \
        gd
RUN apt-get install -y \
        libzip-dev \
        zip \
  &amp;amp;&amp;amp; docker-php-ext-install zip
RUN apt-get update
# 필요한 패키지 설치
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    curl \
    &amp;amp;&amp;amp; apt-get clean \
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    &amp;amp;&amp;amp; docker-php-ext-install pdo_mysql \
    &amp;amp;&amp;amp; docker-php-ext-enable pdo_mysql
# RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD [&quot;php-fpm&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 Extension 별로 enable 과 install 을 해준다.&lt;/li&gt;
&lt;li&gt;해당 과정에서 서비스 에러가 발생할 경우 (ex. not found extension) 에러 구문에 맞는 패키지 설치가 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Nginx Default.conf&lt;/h4&gt;
&lt;pre id=&quot;code_1716530736132&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;server {
    listen 80;
    index index.php index.html;
    server_name localhost;
    root /var/www/public;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    location ~ /\.ht {
        deny all;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nginx 에서 사용할 config 정보를 입력한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;실행방법&lt;/h4&gt;
&lt;pre id=&quot;code_1716530822894&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// docker-compose 파일 내
docker-compose-up -d&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;1472&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OG6Ef/btsHB97Nlt7/GdYkDgR4dXN8Oz1bTvhKn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OG6Ef/btsHB97Nlt7/GdYkDgR4dXN8Oz1bTvhKn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OG6Ef/btsHB97Nlt7/GdYkDgR4dXN8Oz1bTvhKn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOG6Ef%2FbtsHB97Nlt7%2FGdYkDgR4dXN8Oz1bTvhKn0%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;1472&quot; height=&quot;426&quot; data-origin-width=&quot;1472&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;My-laravel-app 터미널 접속&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/20ChY/btsHBAESV8i/sbLzJWMzUcGqThlMKZPsek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/20ChY/btsHBAESV8i/sbLzJWMzUcGqThlMKZPsek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/20ChY/btsHBAESV8i/sbLzJWMzUcGqThlMKZPsek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F20ChY%2FbtsHBAESV8i%2FsbLzJWMzUcGqThlMKZPsek%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;1208&quot; height=&quot;414&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1716530879431&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;composer install
php artisan migrate&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;로컬 구축의 장단점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;장점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터넷 환경에 구애받지 않는 개발 가능&lt;/li&gt;
&lt;li&gt;개발 및 서버 스테이지 환경과 관계없이 개발 가능&lt;/li&gt;
&lt;li&gt;sync 방식의 업로드 형태가 아님에 따른 분리 개발 가능&lt;/li&gt;
&lt;li&gt;서버 이슈와 무관한 개발 가능&lt;/li&gt;
&lt;li&gt;서버 리소스 최소화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 프로젝트와 연관있는 API 통신의 방화벽 정책을 수립해야함&lt;/li&gt;
&lt;li&gt;개발 세팅 리소스 및 러닝커브 발생&lt;/li&gt;
&lt;li&gt;git branch 운용방식의 변화가 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;도커 커맨드 TIPs&lt;/h4&gt;
&lt;pre id=&quot;code_1716532788850&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 도커 내리기
docker-compose down
// 도커 올리기
docker-compose up -d
// 도커 볼륨삭제
docker-compose down --volumes --remove-orphans
// 도커 이미지 강제 삭제
docker image prune --all --force
// 도커 컨테이너 목록
docker ps
// 도커 재빌드
docker-compose build
// 도커 특정 서비스 재시작
docker-compose restart {service}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>PHP</category>
      <category>docker-compose</category>
      <category>Laravel mysql</category>
      <category>laravel redis</category>
      <category>php 개발환경</category>
      <category>도커</category>
      <category>도커서비스</category>
      <category>도커컨테이너</category>
      <category>도커컴포즈</category>
      <category>라라벨로컬개발환경</category>
      <category>윈도우개발환경</category>
      <author>devTak</author>
      <guid isPermaLink="true">https://dev-tak.tistory.com/18</guid>
      <comments>https://dev-tak.tistory.com/18#entry18comment</comments>
      <pubDate>Fri, 24 May 2024 15:11:27 +0900</pubDate>
    </item>
    <item>
      <title>Flutter - 자주 사용하는 위젯 &amp;amp; 클래스</title>
      <link>https://dev-tak.tistory.com/17</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dfryz/btsDARYMU8L/KGKHdlwqSRN12ULEfejt21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dfryz/btsDARYMU8L/KGKHdlwqSRN12ULEfejt21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dfryz/btsDARYMU8L/KGKHdlwqSRN12ULEfejt21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDfryz%2FbtsDARYMU8L%2FKGKHdlwqSRN12ULEfejt21%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;840&quot; height=&quot;345&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;345&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;페이지 이동 - Forward&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// push 를 하게되면 state 위젯을 init 부터 새로 생성한다.
Navigator.of(context).push&amp;lt;int&amp;gt;(
	MaterialPageRoute(builder: (BuildContext context) {
		return &quot;스크린위젯명&quot;;
	})
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;페이지 이동 - Backward&lt;/h2&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;// pop 을 하게되면 이전 페이지로 이동하고 현재 stateFul 클래스는 dispose 된다.
Navigator.of(context).pop();
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;패딩 - Padding&lt;/h2&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;Padding(
	padding: EdgeInsets.{option},
	child: Cloumn()..
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;컬럼 / 로우 - Column Row&lt;/h2&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;Column(
	// 세로 children 들의 여백 옵션
	mainAsixAlignment: MainAsixAlignment.{option},
	// 가로 children 들의 여백 옵션
	crossAxisAlignment : CrossAsixAlignment.{option}, // row mainAsixAlignment(stretch)
	children: []
)

Row(
	// 가로 children 들의 여백 옵션
	mainAsixAlignment: MainAsixAlignment.{option},
	// 세로 children 들의 여백 옵션
	crossAxisAlignment : CrossAsixAlignment.{option}, // cloumn mainAsixAlignment
	children: []
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클라이언트 기기 안전패딩 - SafeArea&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;SafeArea(
	// 아래쪽은 적용하지 않음
	botton: false,
	child: ..
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;슬라이드 - Slider&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;Slider(
	value: ..,
	min: ..,
	max: ..,

	// 콜백 함수은 ValueChanged&amp;lt;double&amp;gt;?
	onChanged: () {
		...
	}
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;버튼 - ElevatedButton&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;ElevatedButton(
	// 콜백 함수은 VoidCallback
	onPressed: () {
		...
	}
	style: ElevatedButton.StyleForm(
		primary: Color();
	),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;버튼 - IconButton&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;IconButton(
	// 콜백 함수은 VoidCallback
	onPressed: () {
		...
	},
	iconSize: 60.0,
	icon: Icon(
		Icons.{option},
		color: Color(),
	),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사이즈 최대확장 - Expanded&lt;/h2&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;Expanded(
	child: Column(
		...
	)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;캔버스 - Scaffold&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;Scaffold(
	backgroundColor: Color(),
	body: ..{}
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;영역그룹핑 - Container&lt;/h2&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;Container(
	child: ..
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클라이언트 환경정보(추측) - MediaQuery&lt;/h2&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;MediaQuery.of(context).{}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Asset 이미지 - Image&lt;/h2&gt;
&lt;pre id=&quot;code_1705538784481&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Image.asset('asset/img/test.png');&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Flutter</category>
      <category>자주사용하는위젯</category>
      <category>플러터</category>
      <category>플러터뒤로가기</category>
      <category>플러터위젯</category>
      <category>플러터클래스</category>
      <category>플러터페이지이동</category>
      <author>devTak</author>
      <guid isPermaLink="true">https://dev-tak.tistory.com/17</guid>
      <comments>https://dev-tak.tistory.com/17#entry17comment</comments>
      <pubDate>Thu, 18 Jan 2024 09:47:00 +0900</pubDate>
    </item>
    <item>
      <title>Flutter Basic Widget Structure</title>
      <link>https://dev-tak.tistory.com/16</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ETWk9/btsDBbosLPH/HfaCBZ2KOaK01KdRxW8Tl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ETWk9/btsDBbosLPH/HfaCBZ2KOaK01KdRxW8Tl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ETWk9/btsDBbosLPH/HfaCBZ2KOaK01KdRxW8Tl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FETWk9%2FbtsDBbosLPH%2FHfaCBZ2KOaK01KdRxW8Tl0%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;842&quot; height=&quot;347&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Flutter 기본 위젯 골격 구조&lt;/h2&gt;
&lt;pre id=&quot;code_1705453090097&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Scaffold : 화이트 캔버스의 역할
return Scaffold(
	// 화이트 캔버스 상단 바를 생성함
	appBar: AppBar(
		title: 'Test APP',
	),
	// 캔버스의 전역적인 배경 색상
	backgroundColor: Colors.pink[100],
	// SafeArea : 모바일 기기의 전반적인 사용 공간을 잡아주는 역할
	body: SafeArea(
	// SafeArea 에서 bottom 영역은 제외
	bottom: false,
	// Container : html 에서 Div와 같은 역할로 생각
	child: Container(
	  // MediaQuery.of : 요청기기의 Spec을 가져올 수 있는 듯
	  width: MediaQuery.of(context).size.width,
	  // Column : 감싸져 있는 위젯을 세로형으로 영역을 나눌 수 있는 위젯
	  child: Column(
	    //column children의 간격을 지정해 줄 수 있는 기능
	    mainAxisAlignment: MainAxisAliment.spaceBetween,
        
	    // Column &amp;amp; Row 는 Children 을 기본적으로 사용할 수 있음
	    children: [
	        // colums 의 비율을 전체적으로 가져갈 수 있도록 해주는 위젯
	        Expanded: (
	            child: _TopPart(
	                selectedDate: selectedDate,
	                onPressed: onHeartPressed,
	            ),
	        ),
	        _BottomPart(),
	    ],
	  ),
	),
));&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;mainAxisAlignment - 주축정렬(전체를 잡아둔다)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;start : 시작&lt;/li&gt;
&lt;li&gt;end : 끝&lt;/li&gt;
&lt;li&gt;center : 가운데&lt;/li&gt;
&lt;li&gt;spaceBetween : 위젯과 위젯의 사이가 동일하게 배치&lt;/li&gt;
&lt;li&gt;spaceEvenly : 위젯을 같은 간격으로 배치하지만 끝과 끝에도 빈간격으로 시작&lt;/li&gt;
&lt;li&gt;spaceAround : 위젯을 같은 간격으로 배치하지만 끝과 끝의 간격은 반간격으로 시작&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CrossAxisAlignment - 반대축 정렬(기본값은 center)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stretch : 최대한으로 늘린다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MediaQuery.*of*(context) 는 클라이언트 정보를 가져오는듯&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MainAxisSize - 주축크기&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;max : 최대&lt;/li&gt;
&lt;li&gt;min : 최소&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Expanded / Flexible - Row 나 Column Children 위젯에서만 사용가능한 속성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Expended - 남아있는 공간을 전부 먹어버린다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;flex : 남아 있는 공간을 비율로 나눌 수 있다. - 기본값 1&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flexible - 남는 공간은 모두 버리고, 설정한 값으로만 세팅한다&lt;/p&gt;</description>
      <category>Flutter</category>
      <category>flutter</category>
      <category>mainaxisalignment</category>
      <category>MediaQuery</category>
      <category>scaffold</category>
      <category>Widget</category>
      <author>devTak</author>
      <guid isPermaLink="true">https://dev-tak.tistory.com/16</guid>
      <comments>https://dev-tak.tistory.com/16#entry16comment</comments>
      <pubDate>Wed, 17 Jan 2024 10:06:05 +0900</pubDate>
    </item>
    <item>
      <title>Flutter 지원 클래스 / Stateless, Stateful Life Cycle</title>
      <link>https://dev-tak.tistory.com/15</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0t2Cj/btsDz8Tmevx/bknQNJK0OBEugrzdT31811/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0t2Cj/btsDz8Tmevx/bknQNJK0OBEugrzdT31811/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0t2Cj/btsDz8Tmevx/bknQNJK0OBEugrzdT31811/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0t2Cj%2FbtsDz8Tmevx%2FbknQNJK0OBEugrzdT31811%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;842&quot; height=&quot;347&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Flutter 다양한 객체 및 옵션 설명&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;SafeArea&lt;/b&gt; : 화면 전체에 대한 기본 area를 지정할 수 있음&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;SafeArea(
        bottom: false,
        child: Container(
&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;size18&quot;&gt;&lt;b&gt;mainAxisAlignment&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;start : 시작&lt;/li&gt;
&lt;li&gt;end : 끝&lt;/li&gt;
&lt;li&gt;center : 가운데&lt;/li&gt;
&lt;li&gt;spaceBetween : 위젯과 위젯의 사이가 동일하게 배치&lt;/li&gt;
&lt;li&gt;spaceEvenly : 위젯을 같은 간격으로 배치하지만 끝과 끝에도 빈간격으로 시작&lt;/li&gt;
&lt;li&gt;spaceAround : 위젯을 같은 간격으로 배치하지만 끝과 끝의 간격은 반간격으로 시작&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CrossAxisAlignment&lt;/b&gt; - 반대축 정렬(기본값은 center)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stretch : 최대한으로 늘린다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MediaQuery.*of*(context) 는 클라이언트 정보를 가져오는 객체&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;MainAxisSize&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;max : 최대&lt;/li&gt;
&lt;li&gt;min : 최소&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Expanded / Flexible - Row 나 Column Children 위젯에서만 사용가능한 속성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Expended&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;flex : 남아 있는 공간을 비율로 나눌 수 있다. - 기본값 1&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Flexible&lt;/b&gt; - 남는 공간은 모두 버리고, 설정한 값으로만 세팅한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;StatefulWidget&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위젯 이론
&lt;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;/li&gt;
&lt;li&gt;&lt;b&gt;StatelessWidget Life Cycle&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Constructor로 생성이되고 생성이 되자마자 build 함수가 실행된다.&lt;/li&gt;
&lt;li&gt;이전 Container 예제와 마찬가지로 변경이 필요하면 새로운 위젯을 만들어버린다.&lt;/li&gt;
&lt;li&gt;하나의 StatelessWidget은 라이프 사이클동안 단 한번만 build 함수를 실행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;StatefulWidget Life Cycle&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Constructor 가 불린다.&lt;/li&gt;
&lt;li&gt;CreateState를 만듬 (최초 1회)&lt;/li&gt;
&lt;li&gt;State.initStatus 를 부름 (1회)&lt;/li&gt;
&lt;li&gt;State.dudChangeDependencies 를 부름&lt;/li&gt;
&lt;li&gt;State.dirty &amp;rarr; &lt;a href=&quot;http://State.build&quot;&gt;State.build&lt;/a&gt; &amp;rarr; State.clean
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;삭제 : deactivate &amp;rarr; dispose&lt;/li&gt;
&lt;li&gt;생성 : setState&lt;/li&gt;
&lt;li&gt;수정 : didUpdateWidget&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;State 객체는 체이닝처럼 기존 State를 재활용한다.&lt;/li&gt;
&lt;li&gt;StateWidget 자체는 무조건 삭제되고 새로 생성된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;StateFulWidget 은 결국은 내부 프로퍼티 데이터들이 유지된다.&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Why : 상태 프로퍼티를 관리하는 것은 State 객체 이므로 State 객체는 재활용됨에 따른 내부 상태 프로퍼티들을 유지할 수 있다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;예제코드&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({required this.color, Key? key}) : super(key: key);

  final Color color;

  @override
  State&amp;lt;HomeScreen&amp;gt; createState() =&amp;gt; _HomeScreenState();
}

class _HomeScreenState extends State&amp;lt;HomeScreen&amp;gt; {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50.0,
      color: widget.color,
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Flutter</category>
      <category>flutter</category>
      <category>lifecycle</category>
      <category>stateful</category>
      <category>Stateless</category>
      <category>생명주기</category>
      <author>devTak</author>
      <guid isPermaLink="true">https://dev-tak.tistory.com/15</guid>
      <comments>https://dev-tak.tistory.com/15#entry15comment</comments>
      <pubDate>Tue, 16 Jan 2024 09:12:07 +0900</pubDate>
    </item>
    <item>
      <title>SpringBoot  + Thymleaf + H2Database 프로젝트 세팅</title>
      <link>https://dev-tak.tistory.com/13</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1073&quot; data-origin-height=&quot;219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SyT1j/btsdWmQYpmp/5b23pIVI31Eqw8vkiil0a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SyT1j/btsdWmQYpmp/5b23pIVI31Eqw8vkiil0a1/img.png&quot; data-alt=&quot;출처 :&amp;amp;nbsp;https://spring.io/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SyT1j/btsdWmQYpmp/5b23pIVI31Eqw8vkiil0a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSyT1j%2FbtsdWmQYpmp%2F5b23pIVI31Eqw8vkiil0a1%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;1073&quot; height=&quot;219&quot; data-origin-width=&quot;1073&quot; data-origin-height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;nbsp;https://spring.io/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h1 data-pm-slice=&quot;1 1 []&quot;&gt;세팅&lt;/h1&gt;
&lt;div data-panel-type=&quot;info&quot;&gt;
&lt;div data-panel-content=&quot;true&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Guide : &lt;a href=&quot;https://spring.io/guides&quot;&gt;https://spring.io/guides&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;스프링 공식 튜토리얼: &lt;a href=&quot;https://spring.io/guides/gs/serving-web-content/&quot;&gt;https://spring.io/guides/gs/serving-web-content/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;스프링부트 메뉴얼: &lt;a href=&quot;https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/&quot;&gt;https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Project Generate&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;geneate : &lt;a href=&quot;https://start.spring.io/&quot;&gt;Spring-Initializr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-node-type=&quot;mediaSingle&quot; data-layout=&quot;center&quot; data-width=&quot;&quot; data-pm-slice=&quot;0 0 []&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;819&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZeNry/btsdXcGnt1S/LGRQV8XFDkKHfIOMIeMADk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZeNry/btsdXcGnt1S/LGRQV8XFDkKHfIOMIeMADk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZeNry/btsdXcGnt1S/LGRQV8XFDkKHfIOMIeMADk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZeNry%2FbtsdXcGnt1S%2FLGRQV8XFDkKHfIOMIeMADk%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;1500&quot; height=&quot;819&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;819&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;3.0 버전 이후 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필수 Dependencies 설치&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Spring Web : 스프링을 사용하는데 기본적인 디펜던시 패키지 모음&lt;/li&gt;
&lt;li&gt;Thymeleaf : BladeTemplate 처럼 요즘 Spring 기반의 프로젝트에서 많이 쓰는 템플릿엔진&lt;/li&gt;
&lt;li&gt;Spring Data JPA : Spring 에서 ORM 으로 데이터를 조작할 수 있는 기술
&lt;ol style=&quot;list-style-type: decimal;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Java Persistent API : 구현을 가능하게 하는 코어 기술&lt;/li&gt;
&lt;li&gt;Hibernate : 코드측면에서 사용가능하게 하는 기술&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;H2Database : Mysql 보다 스터디나 토이프로젝트에 적합한 DBMS&lt;/li&gt;
&lt;li&gt;Lombok : 스프링에 Annotation 확장 기능&lt;/li&gt;
&lt;li&gt;Validation : Test 코드에서 validation 을 쉽게 해주는 패키지&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;Spring-Data-JPA&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;986&quot; data-ke-size=&quot;size23&quot;&gt;Spring Data JPA&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBBUQb/btsdXv6JLhw/GChJsa93t10jmk2aKfsfj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBBUQb/btsdXv6JLhw/GChJsa93t10jmk2aKfsfj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBBUQb/btsdXv6JLhw/GChJsa93t10jmk2aKfsfj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBBUQb%2FbtsdXv6JLhw%2FGChJsa93t10jmk2aKfsfj0%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;600&quot; height=&quot;288&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&quot;Lombok&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1008&quot; data-ke-size=&quot;size23&quot;&gt;Lombok&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1566&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bv2YUg/btsdWOlwc3L/QxesEYIgKB3w160RgHAZn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bv2YUg/btsdWOlwc3L/QxesEYIgKB3w160RgHAZn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bv2YUg/btsdWOlwc3L/QxesEYIgKB3w160RgHAZn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbv2YUg%2FbtsdWOlwc3L%2FQxesEYIgKB3w160RgHAZn1%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;1566&quot; height=&quot;373&quot; data-origin-width=&quot;1566&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;Thymeleaf&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Spring 을 위한 기능들이 지원&lt;/li&gt;
&lt;li&gt;Natural templates
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;markup을 깨지 않고 쓸 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;thymeleaf 공식 사이트: &lt;a href=&quot;https://www.thymeleaf.org/&quot;&gt;https://www.thymeleaf.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;스프링 부트 thymeleaf viewName 매핑&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;resources:templates/ +{ViewName}+ .html&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1683183067300&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Controller
public class HelloController {
    @GetMapping(&quot;hello&quot;)
    public String hello(Model model) {
        model.addAttribute(&quot;data&quot;, &quot;hello!!&quot;);
        return &quot;hello&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;/Resource/templates&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1683183080141&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE HTML&amp;gt;
&amp;lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&amp;gt;
&amp;lt;head&amp;gt;
 &amp;lt;title&amp;gt;Hello&amp;lt;/title&amp;gt;
 &amp;lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot; /&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;p th:text=&quot;'안녕하세요. ' + ${data}&quot; &amp;gt;안녕하세요. 손님&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;Spring Boot DevTools&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 [&amp;quot;panel&amp;quot;,{&amp;quot;panelType&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;panelIcon&amp;quot;:null,&amp;quot;panelIconId&amp;quot;:null,&amp;quot;panelIconText&amp;quot;:null,&amp;quot;panelColor&amp;quot;:null}]&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;스프링부트를 사용하면서, 개발환경에서 개발할 때 용이한 패키지&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpbyQi/btsdXPcPbBK/iVnLYRohuI8SKoGrdzXxIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpbyQi/btsdXPcPbBK/iVnLYRohuI8SKoGrdzXxIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpbyQi/btsdXPcPbBK/iVnLYRohuI8SKoGrdzXxIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdpbyQi%2FbtsdXPcPbBK%2FiVnLYRohuI8SKoGrdzXxIK%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;874&quot; height=&quot;289&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;289&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-pm-slice=&quot;3 1 []&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;캐시초기화&lt;/li&gt;
&lt;li&gt;파일에 대한 서버 재시작 없이 컴파일 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;devtools 를 사용하면 특정 파일만 재컴파일 가능하게 제공해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;Build &amp;gt; Recompile &amp;ldquo;hello.html&amp;rdquo;&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size26&quot;&gt;IDE Package Build&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인텔리제이&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;인텔리제이 실행&lt;/li&gt;
&lt;li&gt;generate 한 패키지 세팅 압축해제&lt;/li&gt;
&lt;li&gt;인텔리제이 오픈 후 패키지 build.gradle 오픈&lt;/li&gt;
&lt;li&gt;package initialize 자동 실행&lt;/li&gt;
&lt;li&gt;settings 에 들어가서 annotation processor 에 enable annotation processing 을 체크해준다&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Vscode&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Extension Pack for Java 설치&lt;/li&gt;
&lt;li&gt;Debugger for Java 설치&lt;/li&gt;
&lt;li&gt;Gradle for Java 설치&lt;/li&gt;
&lt;li&gt;Lombok Annotations Support for VS Code&lt;/li&gt;
&lt;li&gt;프로젝트 빌드 및 실행&lt;/li&gt;
&lt;li&gt;package initialize 자동 실행&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;346&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cduhP8/btsdR3jKW8E/gakT41qusH6WgbZ51i2TKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cduhP8/btsdR3jKW8E/gakT41qusH6WgbZ51i2TKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cduhP8/btsdR3jKW8E/gakT41qusH6WgbZ51i2TKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcduhP8%2FbtsdR3jKW8E%2FgakT41qusH6WgbZ51i2TKK%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;1000&quot; height=&quot;346&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size26&quot;&gt;H2 Database&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발이나 테스트 용도로 가볍고 편리한 DB, 웹화면 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;INFO&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.h2database.com&quot;&gt;https://www.h2database.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;다운로드 및 설치(버전 : &lt;span&gt;2.1.214&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;데이터베이스 파일 생성 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://localhost:8082/&quot;&gt;http://localhost:8082&lt;/a&gt; 접속&lt;/li&gt;
&lt;li&gt;&lt;span&gt;jdbc:h2:~/{packageName ex. jinwook}&lt;/span&gt;(최초 한번, 세션키 유지한 상태로 실행)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;~/jpashop.mv.db&lt;/span&gt; 파일 생성됨 확인 (사용자디렉토리 내)&lt;/li&gt;
&lt;li&gt;이후 부터는 &lt;span&gt;jdbc:h2:tcp://localhost/~/{packageName ex. jinwook}&lt;/span&gt;으로 접속&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JPA 와 DB 설정, 동작확인&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;선행조건&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;java 설치 (H2는 java 환경에서 돌아감)&lt;/li&gt;
&lt;li&gt;h2.bat 실행&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;947&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dZCkud/btsdWPrxVcM/l0kKOH4TRRjQumPbvN8WkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dZCkud/btsdWPrxVcM/l0kKOH4TRRjQumPbvN8WkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dZCkud/btsdWPrxVcM/l0kKOH4TRRjQumPbvN8WkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdZCkud%2FbtsdWPrxVcM%2Fl0kKOH4TRRjQumPbvN8WkK%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;947&quot; height=&quot;522&quot; data-origin-width=&quot;947&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-pm-slice=&quot;3 3 []&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;최초 123.234.535.243:8082 와 같은 랜덤 아이피로 실행되는데, 최초 실행&lt;/li&gt;
&lt;li&gt;sessionId를 유지한 상태에서 localhost 로 변경&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxtvhh/btsdWNAayGr/gtwdbOB4vsphBe56egt7a0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxtvhh/btsdWNAayGr/gtwdbOB4vsphBe56egt7a0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxtvhh/btsdWNAayGr/gtwdbOB4vsphBe56egt7a0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbxtvhh%2FbtsdWNAayGr%2FgtwdbOB4vsphBe56egt7a0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;668&quot; height=&quot;319&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;Resource JPA H2 연결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;resources &amp;rarr; properties 보다 yml 이 깔끔함&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1683183180632&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  datasource:
    url: jdbc:h2:tcp://localhost/~/jpashop;
    username: sa
    password:
    driver-class-name: org.h2.Driver

  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
#        show_sql: true
        format_sql: true

logging:
  level:
    org.hibernate.sql: debug&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이슈발생 참고링크&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://atoz-develop.tistory.com/entry/H2-Database-%EC%84%A4%EC%B9%98-%EC%84%9C%EB%B2%84-%EC%8B%A4%ED%96%89-%EC%A0%91%EC%86%8D-%EB%B0%A9%EB%B2%95&quot;&gt;https://atoz-develop.tistory.com/entry/H2-Database-%EC%84%A4%EC%B9%98-%EC%84%9C%EB%B2%84-%EC%8B%A4%ED%96%89-%EC%A0%91%EC%86%8D-%EB%B0%A9%EB%B2%95&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://abcdefgh123123.tistory.com/331&quot;&gt;https://abcdefgh123123.tistory.com/331&lt;/a&gt;&lt;/p&gt;</description>
      <category>JAVA</category>
      <category>h2database</category>
      <category>Java</category>
      <category>Spring</category>
      <category>springboot</category>
      <category>springboot setting</category>
      <category>thymleaf</category>
      <category>스프링부트</category>
      <category>스프링부트세팅</category>
      <category>스프링세팅</category>
      <author>devTak</author>
      <guid isPermaLink="true">https://dev-tak.tistory.com/13</guid>
      <comments>https://dev-tak.tistory.com/13#entry13comment</comments>
      <pubDate>Thu, 4 May 2023 15:57:57 +0900</pubDate>
    </item>
    <item>
      <title>Cypress - 클라이언트 테스트 자동화란? + env 동적 전달</title>
      <link>https://dev-tak.tistory.com/12</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yUuBI/btsbn2TVzYY/PMpTnLD8RXqXd03QnYkWNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yUuBI/btsbn2TVzYY/PMpTnLD8RXqXd03QnYkWNK/img.png&quot; data-alt=&quot;출처(https://docs.cypress.io/)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yUuBI/btsbn2TVzYY/PMpTnLD8RXqXd03QnYkWNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyUuBI%2Fbtsbn2TVzYY%2FPMpTnLD8RXqXd03QnYkWNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;297&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처(https://docs.cypress.io/)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;250&quot;&gt;설치&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;h2 id=&quot;Requirement&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;254&quot; data-ke-size=&quot;size26&quot;&gt;Requirement&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NPM &amp;gt;= 5.2.0&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;Ubuntu-/-Debian&quot; style=&quot;color: #000000;&quot; data-renderer-start-pos=&quot;285&quot; data-ke-size=&quot;size23&quot;&gt;Ubuntu / Debian&lt;/h3&gt;
&lt;pre id=&quot;code_1681959643543&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apt-get install libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;CentOS&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;427&quot; data-ke-size=&quot;size23&quot;&gt;CentOS&lt;/h3&gt;
&lt;pre id=&quot;code_1681959657258&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yum install -y xorg-x11-server-Xvfb gtk2-devel gtk3-devel libnotify-devel GConf2 nss libXScrnSaver alsa-lib&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;&amp;gt;_-npm-install&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;544&quot; data-ke-size=&quot;size26&quot;&gt;&amp;gt;_ npm install&lt;/h2&gt;
&lt;pre id=&quot;code_1681959672956&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd /your/project/path

npm install cypress --save-dev&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실행&lt;/h2&gt;
&lt;h2 id=&quot;Browser-Mode&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;621&quot; data-ke-size=&quot;size26&quot;&gt;Browser Mode&lt;/h2&gt;
&lt;pre id=&quot;code_1681959702759&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./node_modules/cypress/bin/cypress open&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;Browser-install-(ubuntu)&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;730&quot; data-ke-size=&quot;size23&quot;&gt;Browser install (ubuntu)&lt;/h3&gt;
&lt;pre id=&quot;code_1681959716619&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb&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;1876&quot; data-origin-height=&quot;706&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t6qoQ/btsbqrsauYw/jUa3ddVK9lKiNVtV7GUnEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t6qoQ/btsbqrsauYw/jUa3ddVK9lKiNVtV7GUnEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t6qoQ/btsbqrsauYw/jUa3ddVK9lKiNVtV7GUnEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft6qoQ%2FbtsbqrsauYw%2FjUa3ddVK9lKiNVtV7GUnEk%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;1876&quot; height=&quot;706&quot; data-origin-width=&quot;1876&quot; data-origin-height=&quot;706&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&quot;Command-Line-Interface-Mode&quot; style=&quot;color: #000000;&quot; data-renderer-start-pos=&quot;903&quot; data-ke-size=&quot;size26&quot;&gt;Command Line Interface Mode&lt;/h2&gt;
&lt;pre id=&quot;code_1681959806021&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx cypress run&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;982&quot; data-origin-height=&quot;544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2fyEO/btsblzSBlM8/xlvosrhdvaB9w7C5PuENo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2fyEO/btsblzSBlM8/xlvosrhdvaB9w7C5PuENo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2fyEO/btsblzSBlM8/xlvosrhdvaB9w7C5PuENo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2fyEO%2FbtsblzSBlM8%2FxlvosrhdvaB9w7C5PuENo1%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;982&quot; height=&quot;544&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;544&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1 id=&quot;CLI-Arguments-전달&quot; style=&quot;color: #000000;&quot; data-renderer-start-pos=&quot;1152&quot;&gt;CLI Arguments 전달&lt;/h1&gt;
&lt;pre id=&quot;code_1681959902921&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./node_modules/cypress/bin/cypress open --env test={test},test1={test1}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드에 Agrs 들을 전달하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1681959926154&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vi cypress.config.js&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1681960010138&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { defineConfig } = require('cypress')
const fs = require('fs-extra')
const path = require('path')

async function getConfigurationByFile(test, test1) {

    const pathToConfigFile = path.resolve('/cypress', 'config', `${file}.json`);

    let readJson =  await fs.readJson(pathToConfigFile).then((config) =&amp;gt; {
        config.env.test = test;
        config.env.test1 = test1;
        
        return config;
    });
    
    return readJson;
}

module.exports = defineConfig({
    e2e: {
        experimentalSessionAndOrigin: true,
        setupNodeEvents(on, config) {
            const test = config.env.test;
            const test1 = config.env.test1;
            return getConfigurationByFile(test, test1);
        },
        video: false,
        screenshotOnRunFailure: false,
    },
})&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;module.exports = defineConfig에서 setupNodeEvents 함수 내 config 데이터를 통해 args 값 GET&lt;/li&gt;
&lt;li&gt;getConfigurationByFile 함수를 통해 args 값 전달&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1681960045878&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 전달 받은 args 값 TEST 에서 사용할 수 있도록 env 세팅
let readJson =  await fs.readJson(pathToConfigFile).then((config) =&amp;gt; {
    config.env.test = test;
    // 전달할 env 값에 args 세팅 ..add
    return config;
});&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;전달받은-Args-테스트에서-사용&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3095&quot; data-ke-size=&quot;size23&quot;&gt;전달받은 Args 테스트에서 사용&lt;/h3&gt;
&lt;pre id=&quot;code_1681960101651&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('############# { 즐거운 테스트 } #############', () =&amp;gt; {
    it('TEST', () =&amp;gt; {
        cy.request({
            method: 'GET',
            url: 'localhost/',
            headers: {
                'accept': 'application/json;charset=UTF-8',  
                'authorize': 'TEST '+Cypress.env('test'),
            },
            ...
    });
});&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Cypress.env('test') 처럼 Cypress 객체를 통해 env 값 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;TEST TIP&lt;/h2&gt;
&lt;h3 id=&quot;FailOnStatusCode&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3625&quot; data-ke-size=&quot;size23&quot;&gt;FailOnStatusCode&lt;/h3&gt;
&lt;pre id=&quot;code_1681960168128&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('############# { 즐거운 테스트 } #############', () =&amp;gt; {
    it('TEST', () =&amp;gt; {
        cy.request({
            method: 'GET',
            url: 'localhost/',
            headers: {
                'accept': 'application/json;charset=UTF-8',  
                'authorize': 'TEST '+Cypress.env('test'),
            },
            failOnStatusCode:false, // 값을 false 로 준다.
            ...
    }).then((response) =&amp;gt; {
        expect(response.body.status).to.eq('422');
    });
});&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 style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;해당 값을 false 로 주지 않으면, 4xx error 관련 then 으로 넘어오지 않아 Debugging 이 어려움&lt;/li&gt;
&lt;li style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;따라서 false 를 주면 then 으로 넘어와 error response 를 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>R&amp;amp;D</category>
      <category>API 클라이언트 테스트</category>
      <category>API테스트</category>
      <category>automation client testing</category>
      <category>Cypress</category>
      <category>cypress env</category>
      <category>싸이프레스</category>
      <category>테스팅자동화</category>
      <author>devTak</author>
      <guid isPermaLink="true">https://dev-tak.tistory.com/12</guid>
      <comments>https://dev-tak.tistory.com/12#entry12comment</comments>
      <pubDate>Thu, 20 Apr 2023 12:13:36 +0900</pubDate>
    </item>
    <item>
      <title>SpringBoot APM - Prometheus 란?</title>
      <link>https://dev-tak.tistory.com/11</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;651&quot; data-origin-height=&quot;195&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQZK0B/btsbk64behf/pqJNAbSdOintq2Te1e33K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQZK0B/btsbk64behf/pqJNAbSdOintq2Te1e33K1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQZK0B/btsbk64behf/pqJNAbSdOintq2Te1e33K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQZK0B%2Fbtsbk64behf%2FpqJNAbSdOintq2Te1e33K1%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;651&quot; height=&quot;195&quot; data-origin-width=&quot;651&quot; data-origin-height=&quot;195&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;APM 이란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Application Perfomance Manager&lt;/li&gt;
&lt;li&gt;성능관리모니터링 시스템이라고 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;APM OpenSource&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 85px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;maven repo&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;github star&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;구글 검색 결과&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;pinpoint&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;237&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;12,700&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;약 226,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;scouter&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;16&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;1,900&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;약 77,900&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;prometheus&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;532&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;47,400&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;약 721,000&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;elasticAPM&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;314&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;약 485,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Prometheus(프로메테우스)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오픈 소스 시스템 모니터링 및 경고 ToolKit&lt;/li&gt;
&lt;li&gt;Exporter 로 부터 데이터를 수집하여 데이터를 시각화한다.&lt;/li&gt;
&lt;li&gt;Pull 방식의 Metric 데이터를 수집한다.&lt;/li&gt;
&lt;li&gt;PromQL 방식의 시계열 쿼리 및 집계한다.&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;824&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vf4N9/btsbqtcsIhH/pspQhNDKByRYKhtBePFXKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vf4N9/btsbqtcsIhH/pspQhNDKByRYKhtBePFXKk/img.png&quot; data-alt=&quot;출처(프로메테우스 공식 홈페이지)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vf4N9/btsbqtcsIhH/pspQhNDKByRYKhtBePFXKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvf4N9%2FbtsbqtcsIhH%2FpspQhNDKByRYKhtBePFXKk%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;824&quot; height=&quot;470&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처(프로메테우스 공식 홈페이지)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Setting&lt;/h3&gt;
&lt;pre id=&quot;code_1681959042577&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# my global config
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - &quot;first_rules.yml&quot;
  # - &quot;second_rules.yml&quot;

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=&amp;lt;job_name&amp;gt;` to any timeseries scraped from this config.
  - job_name: &quot;prometheus&quot;
    metrics_path: '/v1/actuator/prometheus'
    scrape_interval: 5s

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: [&quot;localhost:8082&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;scrpe_configs : 스크랩할 서버(Exporter) 설정 정보&lt;/li&gt;
&lt;li&gt;sarape_interval : 메트릭 정보 스크랩 수집 간격&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;GUI&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1878&quot; data-origin-height=&quot;795&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdOfKR/btsblqn6Hxr/0xoBWuYx61gTIiWytLbiA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdOfKR/btsblqn6Hxr/0xoBWuYx61gTIiWytLbiA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdOfKR/btsblqn6Hxr/0xoBWuYx61gTIiWytLbiA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdOfKR%2Fbtsblqn6Hxr%2F0xoBWuYx61gTIiWytLbiA0%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;1878&quot; height=&quot;795&quot; data-origin-width=&quot;1878&quot; data-origin-height=&quot;795&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;메트릭 정보&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Metric Type&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Counter&lt;/li&gt;
&lt;li&gt;Guage&lt;/li&gt;
&lt;li&gt;Histogram&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;Counter&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1449&quot; data-ke-size=&quot;size20&quot;&gt;Counter&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0부터 시작하여, 증가할 수 있는 누적 메트릭&lt;/li&gt;
&lt;li&gt;EX : 요청 수 및 완료 된 작업 수&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;Guage&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1514&quot; data-ke-size=&quot;size20&quot;&gt;Guage&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 숫자 값을 나타내는 메트릭&lt;/li&gt;
&lt;li&gt;현재 메모리 사용량, 동시 요청 수 등 증감이 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;Histogram&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1576&quot; data-ke-size=&quot;size20&quot;&gt;Histogram&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구간별 데이터 취합에 특화되어있는 메트릭&lt;/li&gt;
&lt;li&gt;EX : 히트맵, 구간별 분포 그래프&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;Summary&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1639&quot; data-ke-size=&quot;size20&quot;&gt;Summary&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;히스토그램과 유사하나, 정확한 계산 비용이 발생&lt;/li&gt;
&lt;li&gt;EX : 분위수 단위 계산 값을 볼 때 사용&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>R&amp;amp;D</category>
      <category>apm</category>
      <category>Grafana</category>
      <category>Metric</category>
      <category>Prometheus</category>
      <category>springboot</category>
      <category>모니터링</category>
      <category>프로메테우스</category>
      <author>devTak</author>
      <guid isPermaLink="true">https://dev-tak.tistory.com/11</guid>
      <comments>https://dev-tak.tistory.com/11#entry11comment</comments>
      <pubDate>Thu, 20 Apr 2023 11:57:17 +0900</pubDate>
    </item>
  </channel>
</rss>