<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>j_jeong2.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 04 Nov 2025 12:00:20 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>j_jeong2.log</title>
            <url>https://velog.velcdn.com/images/j_jeong2/profile/b702a37a-31e9-4221-aeff-de13dfa75d7c/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. j_jeong2.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/j_jeong2" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Dart] Dart 시작하기 - Data Type]]></title>
            <link>https://velog.io/@j_jeong2/Dart-Dart-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-Data-Type</link>
            <guid>https://velog.io/@j_jeong2/Dart-Dart-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-Data-Type</guid>
            <pubDate>Tue, 04 Nov 2025 12:00:20 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/j_jeong2/post/8ffda9e6-3868-428b-bb06-5a73c62f7e08/image.png" alt=""></p>
<h1 id="객체-지향-언어-dart">객체 지향 언어 dart</h1>
<ul>
<li>아래 자료형을 포함한 대부분의 자료형과 function은 object, class로 이루어져 있음</li>
</ul>
<pre><code class="language-dart">void main() {
  String name = &quot;쩡&quot;;
  bool alive = true;
  int age = 11;
  double money = 1.11;

  // num : int와 double의 부모 class
  num x = 1;
  x = 1.2;
}</code></pre>
<h1 id="list">list</h1>
<h2 id="list-변수를-만드는-두가지-방법">list 변수를 만드는 두가지 방법</h2>
<ol>
<li><code>var</code> 키워드 사용<pre><code class="language-dart">void main() {
var numbers = [1, 2, 3, 4];
}</code></pre>
</li>
<li><code>List&lt;int&gt;</code> 명시<pre><code class="language-dart">void main() {
List&lt;int&gt; numbers = [1, 2, 3, 4];
}</code></pre>
</li>
</ol>
<ul>
<li>List는 collection if, collection for를 지원<h3 id="collection-if">collection if</h3>
if로 존재할 수도, 존재하지 않을 수도 있는 요소로 작성 가능<pre><code class="language-dart">void main() {
var giveMeFive = true;
var numbers = [
  1,
  2,
  3,
  4,
  if (giveMeFive) 5, // == if(giveMeFive) {numbers.add(5);}
];
print(numbers);
}</code></pre>
</li>
<li>giveMeFive 값이 true일 경우 5를 리스트 요소로 가짐</li>
</ul>
<h3 id="collection-for">collection for</h3>
<pre><code class="language-dart">void main() {
  var oldFriends = [&#39;nico&#39;, &#39;쩡&#39;];
  var newFriends = [
    &#39;lewis&#39;,
    &#39;ralph&#39;,
    &#39;darren&#39;,
    for (var friend in oldFriends) &quot;🩵 $friend&quot;,
  ];
  //   for (var friend in oldFriends) {
  //     newFriends.add();
  //   } collection for를 사용하여 대체 가능
  print(newFriends);
}</code></pre>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/d26d1751-5bfd-48b4-85ee-b2a92e102cea/image.png" alt=""></p>
<ul>
<li>collection if는 메뉴나 navigation bar를 만들 때 유용하게 사용 가능</li>
</ul>
<h4 id="list-자동-formatting-방법">List 자동 Formatting 방법</h4>
<ol>
<li>리스트의 마지막 변수 뒤에 ,(쉼표)를 붙인다.</li>
<li>코드를 전체 선택 단축키(Ctrl+A)를 이용해서 전체 선택한다.</li>
<li>자동 Formatting 단축키 (Shift+Ctrl+F)를 사용.</li>
</ol>
<h1 id="string-interpolation">String interpolation</h1>
<p>String interpolation : text에 변수 추가</p>
<h3 id="단순-변수-값을-출력하고-싶을-때-string-interpolation">단순 변수 값을 출력하고 싶을 때 String interpolation</h3>
<pre><code class="language-dart">void main() {
  var name = &quot;쩡&quot;;
  var greeting = &#39;Hello everyone, my name is $name. Nice to meet you!&#39;;
  print(greeting);
}</code></pre>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/aed5efdb-9222-4827-bd89-0667667bfeef/image.png" alt=""></p>
<ul>
<li>변수가 이미 존재할 경우 $ 기호를 사용 -&gt; <code>$변수명</code></li>
</ul>
<h3 id="계산을-실행할-때-string-interpolation">계산을 실행할 때 String interpolation</h3>
<pre><code class="language-dart">void main() {
  var name = &quot;쩡&quot;;
  var age = 23;
  var greeting = &#39;Hello everyone, my name is $name and I\&#39;m ${age + 2}.&#39;;
  print(greeting);
}</code></pre>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/13434026-f0d8-4fdc-9e5c-cf9e4c9f84ea/image.png" alt=""></p>
<ul>
<li>중괄호 사용 -&gt; <code>${계산할 내용}</code></li>
</ul>
<h1 id="map">Map</h1>
<p>map : key와 value를 연결하는 객체, 동일한 값을 여러번 사용할 수 있음(== Javascript/TypeScript의 object, python의 dictionary)</p>
<pre><code class="language-dart">void main() {
  //   var player = {&#39;name&#39;: &#39;쩡&#39;, &#39;xp&#39;: 99.01, &#39;superpower&#39;: false};
  // key: String, Value: object(any) -&gt; 컴파일러가 자료형 유추
  Map&lt;int, bool&gt; player = {1: true, 2: false, 3: true};
  Map&lt;List&lt;int&gt;, bool&gt; boolean = {
    [1, 2, 3, 5]: true,
  };

  List&lt;Map&lt;String, Object&gt;&gt; players = {
    {
      &#39;name&#39;: &#39;nico&#39;,
      &#39;xp&#39;: 10000.1,
    },
    {
      &#39;name&#39;: &#39;nico&#39;,
      &#39;xp&#39;: 10000.1,
    },
  }
}</code></pre>
<ul>
<li>key와 value로 이루어진 API 구조의 데이터를 정의할 때 Map 대신 class를 사용하는 것이 더 좋음</li>
</ul>
<h1 id="set">Set</h1>
<p>Set과 List의 차이</p>
<ul>
<li>Set에 속한 모든 아이템은 Unique, Sequence(순서가 있음)</li>
<li>중괄호 사용</li>
<li>요소가 항상 하나씩만 있어야 하면 사용</li>
<li>List = python의 list / Set = python의 Tuple</li>
<li>*[Set]**<pre><code class="language-dart">void main() {
 var numbers = {1, 2, 3, 4};
 // == Set&lt;int&gt; numbers = {1, 2, 3, 4,};
 numbers.add(1);
 print(numbers);
}</code></pre>
<img src="https://velog.velcdn.com/images/j_jeong2/post/0d46eebe-97d3-48bb-9efd-d031f710d418/image.png" alt=""></li>
<li>*[List]**<pre><code class="language-dart">void main() {
 List numbers = [1, 2, 3, 4];
 numbers.add(1);
 print(numbers);
}</code></pre>
<img src="https://velog.velcdn.com/images/j_jeong2/post/3fb272ee-416d-4566-9787-103401679b6d/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dart] Dart 시작하기 - Variables]]></title>
            <link>https://velog.io/@j_jeong2/Dart-Dart-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-Variables</link>
            <guid>https://velog.io/@j_jeong2/Dart-Dart-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-Variables</guid>
            <pubDate>Sat, 01 Nov 2025 15:40:38 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/j_jeong2/post/ad93f0df-97ce-43f1-8910-63b686d49d4c/image.png" alt=""></p>
<h1 id="수정-가능한-변수---var">수정 가능한 변수 - var</h1>
<ol>
<li>var 변수<pre><code class="language-dart">void main(){
 var name = &#39;쩡&#39;;
}</code></pre>
</li>
</ol>
<ul>
<li>함수나 메소드 내부에 지역 변수 선언 시 사용</li>
</ul>
<ol start="2">
<li>명시적으로 변수 타입 지정<pre><code class="language-dart">void main(){
 String name = &#39;쩡&#39;;
}</code></pre>
</li>
</ol>
<ul>
<li>클래스에서 변수나 프로퍼티 선언 시 사용</li>
</ul>
<h1 id="dynamic-type">Dynamic Type</h1>
<p>dynamic : 여러가지 타입을 가질 수 있는 변수에 사용되는 키워드 (자주 사용하는 것을 추천하지 않음)</p>
<pre><code class="language-dart">void main() {
  var name; // == dynamic name;
  name = &#39;쩡&#39;;
  name = 1;
  name = true;
}
</code></pre>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/0bbf633e-9059-4cc6-a74f-8cb64c5620f9/image.png" alt=""></p>
<ul>
<li>변수 타입을 알기 어려울 경우 주로 사용</li>
<li>flutter, json 사용 시 dynamic 타입 사용</li>
<li><blockquote>
<p>변수 타입이 지정되지 않아 사용할 수 있는 함수가 많지 않음</p>
</blockquote>
<pre><code class="language-dart">void main() {
 dynamic name;
 if(name is String){
   name.
 }
}
</code></pre>
</li>
</ul>
<pre><code>![](https://velog.velcdn.com/images/j_jeong2/post/d5590f91-a92d-445d-a8de-04994828eff3/image.png)

# Nullable (null safety)
기본적으로 모든 변수는 non-nullable임
null safety : 개발자가 null 값을 참조할 수 없도록 하는 것

```dart
void main() {
  String? nico = &#39;nico&#39;;
  nico = null;
  //   if (nico != null) {
  //     nico.isNotEmpty; // 컴파일러가 null이 아님을 알기 때문에 에러가 나지 않음
  //   }
  nico?.isNotEmpty;
}
</code></pre><ul>
<li>변수 타입에 &#39;?&#39;를 붙이게 되면 해당 변수가 지정한 변수 타입 또는 null이 될 수 있다고 명시하는 것 (A or null)<pre><code class="language-dart">void main() {
String? nico = &#39;nico&#39;;
nico = null;
nico.length;
}</code></pre>
<img src="https://velog.velcdn.com/images/j_jeong2/post/af198422-f50f-41c5-ba52-8c176cabc4f6/image.png" alt=""></li>
</ul>
<h1 id="수정-불가능한-변수---finaljs의-const">수정 불가능한 변수 - final(==js의 const)</h1>
<pre><code class="language-dart">void main() {
  final (String) name = &#39;쩡&#39;;
  name = &#39;hello&#39;;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/5e29dd27-5da8-48ad-8ae0-dad2fdaf4e83/image.png" alt=""></p>
<ul>
<li>타입 지정은 선택</li>
</ul>
<h1 id="late-수식어">late 수식어</h1>
<p>late : final이나 var 앞에 붙여줄 수 있는 수식어로, 초기 데이터 없이 변수를 선언할 수 있도록 해줌</p>
<pre><code class="language-dart">void main() {
  late final name;
  // API 요청으로 데이터 받아옴
  name = &#39;data&#39;;
}</code></pre>
<p><em>flutter에서 data fetching 할 때 유용</em></p>
<h1 id="const">const</h1>
<p>const : compile-time constant를 만들어줌, 수정 불가능한 상수(final과 똑같이 작동), 컴파일 시간에 값이 있어야함
<em>compitle-time constant : 컴파일 시간에 초기화 값을 확인할 수 있는 상수</em></p>
<pre><code class="language-dart">void main() {
  //   const API = &#39;1123344&#39;; // 하드코딩 됨
  const API =
      fetchApi(); // 컴파일러는 api의 변수 값을 모르기 때문에 compile-time constant가 아님 -&gt; final API = fetchApi();로 작성
}</code></pre>
<p>final: 값을 재할당하지 못하는 변수를 만듦
dynamic type: 어떤 타입의 데이터가 들어올 지 모를 때 사용함
const: 컴파일 할 때 값을 알고 있는 변수
final: 런타임 중에 만들어질 수 있는 변수
late: final, var, String같은 것들 앞에 써줄 수 있는 수식어로서 어떤 데이터가 올 지 모를 때 사용한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[VSCode에서 Spring 환경 구축]]></title>
            <link>https://velog.io/@j_jeong2/VSCode%EC%97%90%EC%84%9C-Spring-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95</link>
            <guid>https://velog.io/@j_jeong2/VSCode%EC%97%90%EC%84%9C-Spring-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95</guid>
            <pubDate>Tue, 02 Sep 2025 15:19:00 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/j_jeong2/post/ee320b23-17b1-4f5d-a19e-6808b3413701/image.png" alt=""></p>
<h1 id="스프링-부트-익스텐션-설치-전">스프링 부트 익스텐션 설치 전</h1>
<p>환경 변수 - 시스템 변수 - Path에 jdk 경로가 추가되어있지 않다면 Spring이 실행되지 않으므로 jdk를 설치한 후 Path를 추가해준다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/4cef7be4-f9be-4b2f-b88b-51de205050a7/image.png" alt=""></p>
<h1 id="스프링-부트-익스텐션-설치">스프링 부트 익스텐션 설치</h1>
<p>익스텐션 팩을 설치하게 되면 상단의 Tool, Dashboard, Initializr Java Support 세 개의 익스텐션이 설치된다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/db2cb57b-df5c-4d3d-97b5-a11ad7364452/image.png" alt=""></p>
<h1 id="프로젝트-생성">프로젝트 생성</h1>
<p><code>ctrl + shift + p</code> 를 누른 후, Gradle을 사용하여 프로젝트를 진행할 예정이므로 _<code>Spring Initializr: Create a Gradle Project...</code>_을 선택하여 프로젝트를 생성해준다. 
<img src="https://velog.velcdn.com/images/j_jeong2/post/77a9ea87-e614-4b28-80a1-753c28d00100/image.png" alt="">
사용하고자 하는 버전으로 선택해준다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/bb5d05f9-fde9-424b-b89a-c273f67c33c8/image.png" alt="">
사용하고자 하는 언어로 선택해준다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/97f837c3-6421-4d78-a2e3-fe0c8b4dd566/image.png" alt=""></p>
<h1 id="프로젝트-group-id-설정">프로젝트 Group ID 설정</h1>
<p>Vue.js 프레임워크를 사용하여 프로젝트를 진행해줄 것이기 때문에 그룹 아이디를 <code>parkvue</code>로 설정해주었다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/d5201e74-d4e3-4389-aba7-575a3144ac9a/image.png" alt="">
<img src="https://velog.velcdn.com/images/j_jeong2/post/72477e55-8683-4b59-889c-35ef8f936055/image.png" alt=""></p>
<h1 id="프로젝트-artifact-id-설정">프로젝트 Artifact ID 설정</h1>
<p>디폴트는 demo로 설정되어있다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/2a7689bf-2249-4ddd-ac72-db041959c967/image.png" alt=""></p>
<h1 id="빌드-형식-설정">빌드 형식 설정</h1>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/6fbe222a-a7b0-4393-a1de-a9d63832bbcf/image.png" alt=""></p>
<h1 id="자바-버전-선택">자바 버전 선택</h1>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/dc50f3c6-e444-453a-8430-5a08c5f9817b/image.png" alt=""></p>
<h1 id="의존성-패키지-추가">의존성 패키지 추가</h1>
<p>기본적으로 Spring Web, Lombok, Thymeleaf, Spring Boot DevTools 등을 선택하여 추가한다.
필요한 의존성 패키지가 있으면 검색하여 추가하면 된다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/10ea8fc6-722c-45c3-9ef9-96b1c92464c4/image.png" alt=""></p>
<h1 id="프로젝트-경로-설정">프로젝트 경로 설정</h1>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/8357a07d-8fda-4c53-ba38-41ef97c72280/image.png" alt="">
<code>Generate into this folder</code>를 클릭하여 프로젝트 경로를 설정한 후 우측 하단의 팝업에 <strong><code>Open</code></strong>을 클릭한다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/a76a1bb5-2bad-4136-b378-c878f264a590/image.png" alt="">
open 누르면 새창이 뜨는데 open 안 눌러도 상관은 없을 것 같다.</p>
<h1 id="프로젝트-실행">프로젝트 실행</h1>
<p><code>src-main-java-com-...-ErpApplication.java</code> 파일을 열어 우측 상단의 ▶️Run 버튼을 누르면 Spring이 실행된다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/09f17d08-bc1d-4873-a8dc-b6383c115c6f/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] Vue.js 완벽 마스터 - Vue.js란?]]></title>
            <link>https://velog.io/@j_jeong2/Vue.js-Vue.js-%EC%99%84%EB%B2%BD-%EB%A7%88%EC%8A%A4%ED%84%B0-Vue.js%EB%9E%80</link>
            <guid>https://velog.io/@j_jeong2/Vue.js-Vue.js-%EC%99%84%EB%B2%BD-%EB%A7%88%EC%8A%A4%ED%84%B0-Vue.js%EB%9E%80</guid>
            <pubDate>Wed, 11 Jun 2025 07:36:28 GMT</pubDate>
            <description><![CDATA[<h1 id="🖥️-vuejs란">🖥️ Vue.js란?</h1>
<blockquote>
<p>사용자 인터페이스를 구축하기 위한 JavaScript 프레임워크
표준 HTML, CSS 및 JavaScript를 기반으로 구축되며, 단순한 것 부터 복잡한 것 까지 사용자 인터페이스를 효율적으로 개발할 수 있는 컴포넌트 기반 프로그래밍 모델을 제공
<a href="https://ko.vuejs.org/">https://ko.vuejs.org/</a></p>
</blockquote>
<h3 id="count-버튼-클릭-시-1씩-증가-예시">Count 버튼 클릭 시 1씩 증가 예시</h3>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;script src=&quot;https://unpkg.com/vue@3/dist/vue.global.js&quot;&gt;&lt;/script&gt;
    &lt;title&gt;Vue3&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
        &lt;button type=&quot;button&quot; v-on:click=&quot;counter++&quot;&gt;
            Counter : {{counter}}
        &lt;/button&gt;
    &lt;/div&gt;
    &lt;script&gt;
        const app = Vue.createApp({
            data(){
                return {
                    counter: 0,
                };
            },
        });
        app.mount(&quot;#app&quot;);
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><h3 id="예시에서-알-수-있는-vue의-핵심-기능">예시에서 알 수 있는 Vue의 핵심 기능</h3>
<ul>
<li><strong>선언적 렌더링(Declarative Rendering)</strong> : Vue는 템플릿 구문 <code>{{데이터}}</code>을 활용하여 데이터를 선언적으로 출력(렌더링) 할 수 있도록 함. (자동 렌더링)</li>
<li><strong>반응성(Reactivity)</strong> : Vue는 JavaScript 상태 변경을 자동으로 추적하고 변경이 발생하면 DOM을 효율적으로 업데이트함. -&gt; <code>counter++</code>로 상태 변경 시 <code>{{counter}}</code>에서 자동 변경</li>
</ul>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;script src=&quot;https://unpkg.com/vue@3/dist/vue.global.js&quot;&gt;&lt;/script&gt;
    &lt;title&gt;Document&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
        &lt;input type=&quot;text&quot; v-bind:placeholder=&quot;message&quot;&gt;
        &lt;hr&gt;
        &lt;button v-on:click=&quot;reverseMessage&quot;&gt;
            click
        &lt;/button&gt;
        &lt;hr&gt;
        {{username}} &lt;br&gt;
        &lt;input type=&quot;text&quot; v-model=&quot;username&quot;&gt;
        &lt;hr&gt;
        &lt;p v-if=&quot;visible&quot;&gt;보임&lt;/p&gt;
        &lt;button type=&quot;button&quot; v-on:click=&quot;visible = true&quot;&gt;visible&lt;/button&gt;
        &lt;hr&gt;
        &lt;ul&gt;
            &lt;li v-for=&quot;item in items&quot;&gt;{{item}}&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/div&gt;
    &lt;script&gt;
        const app = Vue.createApp({
            data(){
                return{
                    message: &quot;값을 입력해주세요.&quot;,
                    username: &quot;홍길동&quot;,
                    visible: false,
                    items: [&#39;사과&#39;, &#39;포도&#39;, &#39;딸기&#39;],
                };
            },
            methods:{
                hello(){
                    alert(&#39;Hello World!&#39;);
                },
                reverseMessage(){
                    this.message = this.message.split(&#39;&#39;).reverse().join(&quot;&quot;);
                }
            },
        });
        app.mount(&#39;#app&#39;)
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>※ <code>v-</code> 접두어가 붙은 특수 속성을 <strong>디렉티브(directive)</strong> 라고 함.</p>
<h2 id="바인딩v-bind">바인딩(v-bind)</h2>
<p><code>v-bind</code> 속성은 데이터(상태) 속성에 바인딩할 때 사용하는 특수 속성으로, 바인딩 된 DOM은 <code>placeholder</code> 속성을 Vue 인스턴스의 <code>message</code> 속성으로 최신 상태 유지
하지만 단방향으로 바인딩 되어 input 태그에서 value를 변경 했을 때 상태 값은 변경되지 않음.</p>
<pre><code>&lt;input type=&quot;text&quot; v-bind:placeholder=&quot;message&quot;&gt;

&lt;script&gt;
        const app = Vue.createApp({
            data(){
                return{
                    message: &quot;값을 입력해주세요.&quot;,
                };
            },
        });
        app.mount(&#39;#app&#39;)
&lt;/script&gt;</code></pre><p><img src="https://velog.velcdn.com/images/j_jeong2/post/5fe4692f-6dc1-4f8d-a2d5-30af3488ea63/image.png" alt=""></p>
<h2 id="이벤트-핸들링v-on">이벤트 핸들링(v-on)</h2>
<p>사용자가 앱과 상호 작용할 수 있게 하기 위해 <code>v-on</code> 디렉티브를 사용하여 Vue 인스턴스의 메소드(methods)를 호출</p>
<pre><code>&lt;input type=&quot;text&quot; v-bind:placeholder=&quot;message&quot;&gt;
&lt;hr&gt;
&lt;button v-on:click=&quot;reverseMessage&quot;&gt;click&lt;/button&gt;

&lt;script&gt;
        const app = Vue.createApp({
            methods:{
                reverseMessage(){
                    this.message = this.message.split(&#39;&#39;).reverse().join(&#39;&#39;);
                }
            },
        });
        app.mount(&#39;#app&#39;)
&lt;/script&gt;</code></pre><p><img src="https://velog.velcdn.com/images/j_jeong2/post/b1c998e9-fb6d-4bf0-942a-8bfea6542d8d/image.png" alt="">
<code>버튼을 누르면 message 값이 reverse 되어 나온다.</code></p>
<h2 id="양방향-바인딩v-model">양방향 바인딩(v-model)</h2>
<p>value 변경 시 상태값도 변경하고 싶을 때 <code>v-model</code>로 상태값도 변경 가능</p>
<pre><code>&lt;p&gt;{{username}}&lt;/p&gt;
&lt;input type=&quot;text&quot; v-model=&quot;username&quot;&gt;

&lt;script&gt;
        const app = Vue.createApp({
            data(){
                return{
                    username: &quot;홍길동&quot;,
                };
            },
        });
        app.mount(&#39;#app&#39;)
&lt;/script&gt;</code></pre><p><img src="https://velog.velcdn.com/images/j_jeong2/post/073956ec-0ac7-4fc1-831a-8095b3225a39/image.png" alt=""></p>
<h2 id="조건문v-if">조건문(v-if)</h2>
<pre><code>&lt;p v-if=&quot;visible&quot;&gt;보임&lt;/p&gt;
&lt;button type=&quot;button&quot; v-on:click=&quot;visible = true&quot;&gt;visible&lt;/button&gt;

&lt;script&gt;
        const app = Vue.createApp({
            data(){
                return{
                    visible: false,
                };
            },
        });
        app.mount(&#39;#app&#39;)
&lt;/script&gt;</code></pre><p><img src="https://velog.velcdn.com/images/j_jeong2/post/1e3171ad-d06d-4ace-a5a1-926ec60e09cf/image.png" alt="">
<code>버튼을 누르면 &#39;보임&#39;이라는 글자가 화면에 나타남</code></p>
<h2 id="반복문v-for">반복문(v-for)</h2>
<p><code>v-for</code>는 배열에서 데이터를 가져와 아이템 목록을 표시</p>
<pre><code>&lt;ul&gt;
    &lt;li v-for=&quot;item in items&quot;&gt;{{item}}&lt;/li&gt;
&lt;/ul&gt;

&lt;script&gt;
        const app = Vue.createApp({
            data(){
                return{
                    items: [&#39;사과&#39;, &#39;포도&#39;, &#39;딸기&#39;],
                };
            },
        });
        app.mount(&#39;#app&#39;)
&lt;/script&gt;</code></pre><p><img src="https://velog.velcdn.com/images/j_jeong2/post/95d6087f-1672-4c44-99d1-2c3a519279b6/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLD] 데이터 모델링의 이해]]></title>
            <link>https://velog.io/@j_jeong2/SQLD-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@j_jeong2/SQLD-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Wed, 07 May 2025 05:57:37 GMT</pubDate>
            <description><![CDATA[<h1 id="🪧데이터-모델링">🪧데이터 모델링</h1>
<blockquote>
<ul>
<li>정보시스템을 구축하기 위한 데이터 관점의 업무 분석 기법으로 현실세계의 데이터(what)를 약속된 표기법으로 표현하는 과정이다.</li>
</ul>
</blockquote>
<ul>
<li>데이터베이스를 구축하기 위한 분석 및 설계의 과정이라고 할 수 있다.</li>
</ul>
<h1 id="📄데이터-모델링-목적">📄데이터 모델링 목적</h1>
<blockquote>
<ol>
<li>업무정보를 구성하는 기초 정보들을 일정한 표기법으로 표현하여 정보시스템 구축의 대상이 되는 업무 내용을 정확하게 분석하는 것</li>
<li>분석된 모델로 실제 데이터베이스를 생성하여 개발 및 데이터관리에 사용하기 위한 것</li>
</ol>
</blockquote>
<p>데이터 모델링은 단지 데이터베이스만을 구축하기 위한 용도로 쓰이는 것이 아니라 데이터 모델링 자체로도 업무를 설명하고 분석하는 부분에서 매우 중요한 의미가 있다.</p>
<h1 id="🚨데이터-모델링-유의점">🚨데이터 모델링 유의점</h1>
<h3 id="1-중복duplication">1. 중복(Duplication)</h3>
<ul>
<li>데이터 모델은 같은 데이터를 사용하는 사람, 시간, 그리고 장소를 파악하는 데 도움을 준다.</li>
<li>데이터베이스가 여러 장소에 같은 정보를 저장하는 잘못을 하지 않도록 한다.<h3 id="2-비유연성inflexibility">2. 비유연성(Inflexibility)</h3>
</li>
<li>데이터 모델을 어떻게 설계했느냐에 따라 사소한 업무변화에도 데이터 모델이 수시로 변경되어 유지보수의 어려움을 가중시킬 수 있다.</li>
<li>데이터의 정의를 데이터의 사용 프로세스와 분리함으로써 데이터 모델링은 데이터 혹은 프로세스의 작은 변화가 애플리케이션과 데이터 베이스에 중대한 변화를 일으킬 수 있는 가능성을 줄인다.<h3 id="3-비일관성inconsistency">3. 비일관성(Inconsistency)</h3>
</li>
<li>데이터 중복이 없더라도 비일관성은 발생할 수 있다.</li>
<li>ex) 신용 상태에 대한 갱신 없이 고객의 납무 이력 정보를 갱신하는 경우 → 개발자가 서로 연관된 다른 데이터와 모순된다는 고려 없이 일련의 데이터를 수정할 수 있기 때문에 이와 같은 문제 발생</li>
<li>데이터 모델링을 할 때 데이터와 데이터 간의 상호 연관 관계에 대해 <strong>명확하게 정의</strong>한다면 이러한 위험을 사전에 예방하는데 도움을 줄 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 컴포넌트끼리 값 전달하기]]></title>
            <link>https://velog.io/@j_jeong2/React-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EB%81%BC%EB%A6%AC-%EA%B0%92-%EC%A0%84%EB%8B%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@j_jeong2/React-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EB%81%BC%EB%A6%AC-%EA%B0%92-%EC%A0%84%EB%8B%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 24 Nov 2024 16:30:17 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/j_jeong2/post/fc34dd94-e19b-455a-889d-ad59dfe2d344/image.png" alt=""></p>
<h1 id="오늘의집-클론코딩-컴포넌트끼리-값-전달하기">오늘의집 클론코딩 컴포넌트끼리 값 전달하기</h1>
<p>[storeManagement.js] 코드 일부</p>
<pre><code>import React, {useEffect, useState} from &#39;react&#39;;
import ProductManagement from &quot;./productManagement&quot;;
import InfoUpdate from &quot;./infoUpdate&quot;;
import { SidebarItem } from &#39;./sidebarItem&#39;;
import &#39;../css/store.css&#39;;
import StoreInventory from &quot;./store_inventory&quot;;
import StoreProduct from &quot;./store_product&quot;;
import StoreStatus from &quot;./store_status&quot;;

function StoreManagement() {
    const [productInfo, setProductInfo] = useState(null);
    const [productCount, setProductCount] = useState(null);
// 상품 리스트 불러오기
    const fetchProductInfo = async (storenum) =&gt; {
        try {
            const response = await fetch(`http://localhost:80/product/productList?storenum=${storenum}`, {
                method: &#39;GET&#39;
            });

            if(response.ok){
                const data = await response.json();
                setProductInfo(data);
            }else {
                console.error(&#39;Failed to fetch user info&#39;);
            }
        } catch (error) {
            console.error(&#39;Error fetching user info:&#39;, error);
        }
    };

    // 상품 개수 불러오기
    const fetchProductCount = async (storenum) =&gt; {
        try {
            const response = await fetch(`http://localhost:80/product/productCount?storenum=${storenum}`, {
                method: &#39;GET&#39;
            });
            if(response.ok){
                const data = await response.json();
                setProductCount(data);
            }else {
                console.error(&#39;Failed to fetch user info&#39;);
            }
        } catch (error) {
            console.error(&#39;Error fetching user info:&#39;, error);
        }
    };
&lt;중략&gt;
    &lt;section className=&quot;store-content-section store-item&quot;&gt;
        {/*컴포넌트에 값 전달*/}
        {activeMenu === &quot;상품 관리&quot; &amp;&amp; &lt;StoreProduct productcount={productCount} productinfo={productInfo}/&gt;}
        {activeMenu === &quot;재고 관리&quot; &amp;&amp; &lt;StoreInventory /&gt;}
        {activeMenu === &quot;매출 현황&quot; &amp;&amp; &lt;StoreStatus /&gt;}
        {activeMenu === &quot;정보 변경&quot; &amp;&amp; &lt;InfoUpdate /&gt;}
    &lt;/section&gt;</code></pre><p>db에서 저장한 값을 storeManagement.js 컴포넌트에서 매개변수에 저장시켜주고 store_product.js 컴포넌트로 전달하기 위해 store_product.js를 StoreProduct로 임포트 시켜주고 컴포넌트를 불러온다.</p>
<h4 id="참조-블로그">참조 블로그</h4>
<p><a href="https://velog.io/@sojeong0302/React-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%97%90-%EA%B0%92-%EC%A0%84%EB%8B%AC%ED%95%98%EA%B8%B0">https://velog.io/@sojeong0302/React-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%97%90-%EA%B0%92-%EC%A0%84%EB%8B%AC%ED%95%98%EA%B8%B0</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] 오늘의집 데이터 크롤링]]></title>
            <link>https://velog.io/@j_jeong2/Python-%EC%98%A4%EB%8A%98%EC%9D%98%EC%A7%91-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%81%AC%EB%A1%A4%EB%A7%81</link>
            <guid>https://velog.io/@j_jeong2/Python-%EC%98%A4%EB%8A%98%EC%9D%98%EC%A7%91-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%81%AC%EB%A1%A4%EB%A7%81</guid>
            <pubDate>Sun, 17 Nov 2024 09:28:10 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘의집-쇼핑-카테고리-상품-크롤링">오늘의집 쇼핑 카테고리 상품 크롤링</h1>
<p>국취제 끝나기 직전 마지막 스프링 프로젝트로 오늘의집을 클론코딩하는데, 이때 쓰일 쇼핑 카테고리별 상품을 크롤링하는 코드를 작성했다.</p>
<h3 id="보완할-점">보완할 점</h3>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/39c52944-3238-46bf-a5b5-821ca9458d16/image.png" alt="">
오늘의 집 카테고리는 이렇게 생겼는데, 여기서 메인 카테고리와 하위 카테고리, 구분선 밑의 다른 메인 카테고리의 아이디를 한번에 가져오고 싶었다. 하지만 첫 크롤링인데다가 크롤링 문법에 익숙하지 않아 뭔가 알 것 같은데 해결이 되지 않았다. 그래서 결국은 큰 카테고리의 아이디는 수동으로 입력하고 하위 카테고리는 크롤링으로 가져와서 db에 저장하였다. 큰 카테고리 아이디를 가져오는 방법을 다시 알아봐야겠다.</p>
<pre><code>import re
import time
import mysql.connector
from mysql.connector import Error
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
from bs4 import BeautifulSoup

# MySQL에 카테고리 데이터를 삽입하는 함수
def insertCategory(category_id, majorCategory=None, subCategory=None):
    try:
        # MySQL 데이터베이스 연결
        connection = mysql.connector.connect(
            host=&#39;localhost&#39;,      # MySQL 서버 주소
            user=&#39;&#39;,      # MySQL 사용자명
            password=&#39;&#39;, # MySQL 비밀번호
            database=&#39;&#39;   # 사용할 데이터베이스 이름
        )
        if connection.is_connected():
            cursor = connection.cursor()
            # 데이터 삽입 쿼리
            insert_query = &quot;&quot;&quot;
                INSERT INTO category (categoryNum, majorCategory, subCategory)
                VALUES (%s, %s, %s)
            &quot;&quot;&quot;

            # 쿼리 실행
            cursor.execute(insert_query, (int(category_id), majorCategory, subCategory))
            connection.commit()  # 커밋하여 데이터베이스에 반영
            print(f&#39;카테고리 [{category_id}]가 DB에 저장되었습니다.&#39;)

    except Error as e:
        print(f&#39;오류 발생: {e}&#39;)
    finally:
        if connection.is_connected():
            cursor.close()
            connection.close()  # 데이터베이스 연결 종료

# 판매자정보 삽입 함수
def insertStore(store):
    try:
        # MySQL 데이터베이스 연결
        connection = mysql.connector.connect(
            host=&#39;localhost&#39;,      # MySQL 서버 주소
            user=&#39;root&#39;,           # MySQL 사용자명
            password=&#39;1234&#39;,       # MySQL 비밀번호
            database=&#39;myhouse&#39;     # 사용할 데이터베이스 이름
        )
        if connection.is_connected():
            cursor = connection.cursor()
            # 스토어 중복 여부 확인
            check_query = &quot;SELECT COUNT(*) FROM store WHERE storeName = %s&quot;
            cursor.execute(check_query, (store,))
            count = cursor.fetchone()[0]

            # 중복이 없는 경우에만 삽입
            if count == 0:
                insert_query_store = &quot;INSERT INTO store (storeName) VALUES (%s)&quot;
                cursor.execute(insert_query_store, (store,))
                connection.commit()
                print(f&#39;스토어 [{store}]가 DB에 저장되었습니다.&#39;)
            else:
                print(f&#39;스토어 [{store}]는 이미 DB에 존재합니다.&#39;)
    except Error as e:
        print(f&#39;오류 발생: {e}&#39;)
    finally:
        if connection.is_connected():
            cursor.close()
            connection.close()  # 데이터베이스 연결 종료

# 판매자 번호 가져오기
def get_store_id(store_name):
    try:
        # MySQL 데이터베이스 연결
        connection = mysql.connector.connect(
            host=&#39;localhost&#39;,      # MySQL 서버 주소
            user=&#39;root&#39;,           # MySQL 사용자명
            password=&#39;1234&#39;,       # MySQL 비밀번호
            database=&#39;myhouse&#39;     # 사용할 데이터베이스 이름
        )
        if connection.is_connected():
            cursor = connection.cursor()
            # store_name이 이미 존재하는지 확인
            select_query = &quot;SELECT storeNum FROM store WHERE storeName = %s&quot;
            cursor.execute(select_query, (store_name,))
            result = cursor.fetchone()

            if result:
                # store_name이 이미 존재하면 해당 store_id 반환
                return result[0]
    except Error as e:
        print(f&#39;오류 발생: {e}&#39;)
        return None
    finally:
        if connection.is_connected():
            cursor.close()
            connection.close()  # 데이터베이스 연결 종료

# 상품 삽입 함수
def insertProduct(product_num, product_name, category_id, store_name):
    try:
        # MySQL 데이터베이스 연결
        connection = mysql.connector.connect(
            host=&#39;localhost&#39;,      # MySQL 서버 주소
            user=&#39;root&#39;,           # MySQL 사용자명
            password=&#39;1234&#39;,       # MySQL 비밀번호
            database=&#39;myhouse&#39;     # 사용할 데이터베이스 이름
        )

        store_num = get_store_id(store_name)

        if connection.is_connected():
            cursor = connection.cursor()
            # 상품 중복 여부 확인
            check_query = &quot;SELECT COUNT(*) FROM product WHERE productNum = %s&quot;
            cursor.execute(check_query, (product_num,))
            count = cursor.fetchone()[0]

            # 중복이 없는 경우에만 삽입
            if count == 0:
                # 데이터 삽입 쿼리
                insert_query_product = &quot;INSERT INTO product (productNum, productName, categoryNum, storeNum) VALUES (%s,%s,%s,%s)&quot;
                # 쿼리 실행
                cursor.execute(insert_query_product, (int(product_num), product_name, int(category_id), store_num))
                connection.commit()  # 커밋하여 데이터베이스에 반영
                print(f&#39;상품코드 [{product_num}], 상품명 [{product_name}], 카테고리 [{category_id}], 판매자 [({store_num}), {store}]가 DB에 저장되었습니다.&#39;)
            else:
                print(f&#39;상품명 [{product_name}]는 이미 DB에 존재합니다.&#39;)
    except Error as e:
        print(f&#39;오류 발생: {e}&#39;)
    finally:
        if connection.is_connected():
            cursor.close()
            connection.close()  # 데이터베이스 연결 종료

# 크롬 드라이버 설정
options = Options()
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=options)

# 카테고리 ID가 포함된 URL
base_url = &#39;https://ohou.se/store/category?category_id=&#39;

# 페이지 URL
url = &#39;https://ohou.se/store/category?category_id=34000000&#39;  # 초기 페이지 URL
driver.get(url)
time.sleep(3)  # 페이지 로드 대기

# 페이지 소스를 BeautifulSoup으로 파싱
soup = BeautifulSoup(driver.page_source, &#39;html.parser&#39;)

# 특정 div나 h2 태그 내에서만 a 태그를 찾고 싶다면
h2_elements = soup.find_all(&#39;h2&#39;, class_=&#39;commerce-category-list__title&#39;)
tree_div_elements = soup.find_all(&#39;div&#39;, class_=&#39;commerce-category-tree__entry__header&#39;)

# 각 요소 내에서 a 태그를 찾기
category_links = []
for element in h2_elements + tree_div_elements:
    category_links.extend(element.find_all(&#39;a&#39;, href=True))  # 해당 요소 내에서 모든 a 태그 추가

# 이후 category_id, category_names 추출
category_ids = []
category_names = []

for link in category_links:
    href = link[&#39;href&#39;]
    match = re.search(r&#39;category_id=(\d+)&#39;, href)
    category_name = link.get_text().strip()

    if match:
        category_id = match.group(1)
        if &quot;O!&quot; not in category_name and &quot;렌탈&quot; not in category_name and &quot;수입주방관&quot; not in category_name and category_id not in category_ids:
            category_ids.append(category_id)
            category_names.append(category_name)

# 카테고리 아이디와 이름을 묶어서 딕셔너리로 변환
category_dict = dict(zip(category_ids, category_names))
print(category_dict)

previous_major_category = None

for category_id, category_name in category_dict.items():
    # 세 번째, 네 번째 자리가 &#39;0&#39;이면 majorCategory로 설정
    if (len(category_id) &gt;= 3 and category_id[2] == &#39;0&#39;) and (len(category_id) &gt;= 4 and category_id[2] == &#39;0&#39; and category_id[3] == &#39;0&#39;):
        majorCategory = category_name
        subCategory = None
        previous_major_category = majorCategory
    else:  # 세 번째, 네 번째 자리가 &#39;0&#39;이 아니면 subCategory로 설정
        majorCategory = previous_major_category  # 이전 majorCategory를 그대로 사용
        subCategory = category_name

    # MySQL 데이터베이스에 카테고리 저장
    insertCategory(category_id, majorCategory, subCategory)

# 각 카테고리 ID에 대해 상품 크롤링
for category_id, category_name in category_dict.items():
    # 세 번째 자리가 &#39;0&#39;이 아닌 경우만 크롤링
    if (len(category_id) &gt;= 3 and category_id[2] != &#39;0&#39;) or (len(category_id) &gt;= 4 and category_id[2] == &#39;0&#39; and category_id[3] != &#39;0&#39;):
        target_product_count = 10
        print(f&quot;\n카테고리 {category_id}에서 크롤링 시작&quot;)

        driver.get(base_url + category_id)
        time.sleep(1)

        product_list = []
        product_nums = []

        # 상품 정보 수집
        while len(product_list) &lt; target_product_count:
            soup = BeautifulSoup(driver.page_source, &#39;html.parser&#39;)
            articles = soup.find_all(&#39;article&#39;, class_=&#39;css-fy16k5&#39;)

            for article in articles:
                link = article.find(&#39;a&#39;, href=True)
                if link:
                    href = link[&#39;href&#39;]
                    match = re.search(r&#39;/productions/(\d+)&#39;, href)
                    if match:
                        product_id = match.group(1)
                        if product_id not in product_nums:
                            product_nums.append(product_id)
                            store = article.select_one(&#39;div.product-brand&#39;).get_text().strip()
                            product_name = article.select_one(&#39;span.product-name&#39;).get_text().strip()

                            if &quot;쿠폰&quot; not in product_name:
                                product_list.append({
                                    &#39;productNum&#39;: product_id,
                                    &#39;store&#39;: store,
                                    &#39;product&#39;: product_name
                                })
                                insertStore(store)
                                insertProduct(product_id, product_name, category_id, store)

                            if len(product_list) &gt;= target_product_count:
                                break

            driver.find_element(By.TAG_NAME, &#39;body&#39;).send_keys(Keys.END)
            time.sleep(1)
        print(f&quot;상품: {product_list}&quot;)

# 드라이버 종료
driver.quit()
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[select option 버튼으로 커스텀 하기]]></title>
            <link>https://velog.io/@j_jeong2/select-option-%EB%B2%84%ED%8A%BC%EC%9C%BC%EB%A1%9C-%EC%BB%A4%EC%8A%A4%ED%85%80-%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@j_jeong2/select-option-%EB%B2%84%ED%8A%BC%EC%9C%BC%EB%A1%9C-%EC%BB%A4%EC%8A%A4%ED%85%80-%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 10 Sep 2024 04:50:24 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/j_jeong2/post/2d61848e-627c-4b6a-94ef-38e7145459d5/image.png" alt="select option 커스텀하기"></p>
<h2 id="커스텀-select-box를-만든-계기">커스텀 select box를 만든 계기</h2>
<p>select option 코드를 스크립트로 생성한 후 option의 폰트를 변경하기 위해 구글링을 해서 찾아봤지만 option의 폰트를 바꾸기 위한 글은 찾을 수 없었고 select option 스타일을 변경하여 ul, li 코드를 이용해 셀렉트 박스를 만든 사례가 더 많았다. 그래서 나도 셀렉트 박스의 디자인을 변경하기 위해 다른 분들의 코드들을 보고 코드를 변경해보았다.</p>
<h3 id="html-코드">HTML 코드</h3>
<pre><code>    &lt;div class=&quot;league_season&quot;&gt;
        &lt;button type=&quot;button&quot; class=&quot;selectbox-btn&quot;&gt;시즌 선택&lt;/button&gt;
        &lt;ul class=&quot;selectbox-option&quot;&gt;
            &lt;script&gt;
                let season = 2013;
                let seasonList = [];
                let today = new Date();
                let year = today.getFullYear();
                for (let i = 0; i &lt; 12; i++) {
                    seasonList.push(season + i);
                }
                seasonList.forEach((item) =&gt; {
                    document.write(`&lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;option-btn&quot;&gt;${item}&lt;/button&gt;&lt;/li&gt;`);
                });
            &lt;/script&gt;
        &lt;/ul&gt;
    &lt;/div&gt;</code></pre><h3 id="css-코드">CSS 코드</h3>
<pre><code>.league_season{
    position: relative;
    width: 150px;
    margin: 10px 20px 10px 10px;
    float: right;
}

.selectbox-btn {
    width: 150px;
    padding: 13px 30px 13px 14px;
    font-size: 22px;
    line-height: 14px;
    background-color: #fff;
    border: 1px solid #C4C4C4;
    box-sizing: border-box;
    border-radius: 10px;
    cursor: pointer;
    text-align: left;
    background: url(&quot;../images/select-down_img.png&quot;) center right 10px no-repeat;
    background-size: 14px;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}

.selectbox-option{
    display: none;
    position: absolute;
    width: 100%;
    left: 0;
    border: 1px solid #C4C4C4;
    box-sizing: border-box;
    box-shadow: 4px 4px 14px rgba(0, 0, 0, 0.15);
    border-radius: 10px;
}

.selectbox-btn.on {
    background: url(&quot;../images/select-up_img.png&quot;) center right 10px no-repeat;
    background-size: 14px;
}

.selectbox-btn.on+.selectbox-option {
    display: block;
}

.selectbox-btn li {
    height: 40px;
    padding: 5px 8px;
    box-sizing: border-box;
}

.option-btn{
    width: 100%;
    padding: 10px;
    border: none;
    font-size: 22px;
    background-color: #fff;
    border-radius: 8px;
    cursor: pointer;
    text-align: left;
    /* 말줄임 */
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}

.option-btn:hover, .option-btn:focus{
    background-color: #e4f1ff;
}</code></pre><h3 id="js-코드">JS 코드</h3>
<pre><code>const btn = document.querySelector(&#39;.selectbox-btn&#39;);
const list = document.querySelector(&#39;.selectbox-option&#39;);

btn.addEventListener(&#39;click&#39;, () =&gt; {
    btn.classList.toggle(&#39;on&#39;);
});

list.addEventListener(&#39;click&#39;, (event) =&gt; {
    if (event.target.nodeName === &quot;BUTTON&quot;) {
        btn.innerText = event.target.innerText;
        btn.classList.remove(&#39;on&#39;);
    }
});

window.addEventListener(&#39;click&#39;, (event) =&gt; { 
    if (!btn.contains(event.target)) {
        btn.classList.remove(&#39;on&#39;);
    }
});</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[데이터베이스] HeidiSQL 설치 방법]]></title>
            <link>https://velog.io/@j_jeong2/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-HeidiSQL-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@j_jeong2/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-HeidiSQL-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Wed, 31 Jul 2024 00:41:31 GMT</pubDate>
            <description><![CDATA[<h1 id="heidisql-다운로드">HeidiSQL 다운로드</h1>
<blockquote>
<p><a href="https://www.heidisql.com/download.php">https://www.heidisql.com/download.php</a></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/e5d8d041-fba6-43e9-bded-ac924e38b568/image.png" alt="">
위 링크에 접속한 후 Installer를 클릭해 다운받아줍니다.</p>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/42f15293-3a86-4122-9eb2-cb0a46b00287/image.png" alt="">
exe 파일을 열게 되면 설치 시 보여줄 언어를 선택할 수 있습니다. 한국어는 설치 언어에 없어서 영어로 선택했습니다.</p>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/b992b6b6-da68-48dd-ba44-3c2c4857e1ca/image.png" alt="">
동의 후 다음을 눌러줍니다.</p>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/21ad7dcd-ecb6-4e6b-a461-ade9856d9c70/image.png" alt="">
✔ 바탕화면 바로가기 생성
✔ sql 예제 파일 생성 경로
✔ sql 확장자명을 가진 파일을 heidisql로 연결
✔ 자동 업데이트
✔ 자동으로 heidisql에 보고
취향대로 선택해서 설치하면 될 것 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/f909520a-5ff8-42b6-ad49-dc1c134d6687/image.png" alt="">
Click Finish to exit Setup 선택에 첫 설치 시에는 컴퓨터를 다시시작 할건지 물어보는 라디오버튼이 있는데 No를 누르면 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/46a1d7d2-defe-46b9-aeb1-e036479aa002/image.png" alt="">
<img src="https://velog.velcdn.com/images/j_jeong2/post/ddaab6e2-60e0-41e5-b9e7-7b56a2d89ec8/image.png" alt=""></p>
<p>실행 후 신규를 눌러서 세션을 생성해줍니다. 사용할 네트워크 유형을 선택하고 암호까지 입력하게 되면 데이터베이스 텍스트필드에 있는 파란삼각형을 누르면 위 사진과 같이 뜨는데 mydata 빼고 다 초기에 사용 가능한 데이터베이스입니다. 저는 mysql로 선택해서 저장 후 열기 해줬습니다.</p>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/c634c40e-54a4-4bb7-b6d6-4f61de091011/image.png" alt="">
신규 생성한 세션을 우클릭한 후 데이터베이스 생성을 누르면 새 창이 하나 뜨는데
<img src="https://velog.velcdn.com/images/j_jeong2/post/c59bc5d3-85b5-4071-b418-497a07ad0c1c/image.png" alt="">
데이터베이스 이름을 지정하고 euckr_korean_ci 조합을 선택해서 생성해주면 됩니다.</p>
<p>새로 생성한 데이터베이스를 사용하려면 데이터베이스를 클릭해주어야 연결이 되기 때문에 클릭 후 쿼리문으로 테이블, 데이터 삽입 후 사용하면 됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Web] JDK17/Eclipse/Apache Tomcat 9.0 다운로드 방법]]></title>
            <link>https://velog.io/@j_jeong2/Web-JDK17EclipseApache-Tomcat-9.0-%EB%8B%A4%EC%9A%B4%EB%A1%9C%EB%93%9C-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@j_jeong2/Web-JDK17EclipseApache-Tomcat-9.0-%EB%8B%A4%EC%9A%B4%EB%A1%9C%EB%93%9C-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Tue, 23 Jul 2024 11:43:30 GMT</pubDate>
            <description><![CDATA[<p>국민취업제도 프로그램에서 사용할 개발 소프트웨어 설치 방법입니다.</p>
<h1 id="jdk-17-다운로드">JDK 17 다운로드</h1>
<blockquote>
<p><a href="https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html">https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html</a></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/e6bbf5e6-71bb-4026-bef1-7d2dca97bc8f/image.png" alt="">
오라클 사이트에서 플랫폼을 담당하는 JDK를 다운받아줍니다.
제가 사용하는 운영체제는 윈도우이기 때문에 Windows x64 Installer로 다운받아줍니다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/6eb093e3-dd73-4224-8b10-7f488f8ad77e/image.png" alt="">
exe 파일을 실행시키고 파일 위치를 지정한 후 설치해줍니다. 저는 따로 Java 파일을 만든 후 C:\Java\jdk-17로 위치를 지정해줬는데 기본은 C:\Program Files\Java\jdk-17로 되어 있기 때문에 변경하지 않아도 상관 없습니다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/eae69368-e698-4e67-b56d-7579f6afbed2/image.png" alt=""></p>
<h1 id="이클립스-다운로드">이클립스 다운로드</h1>
<blockquote>
<p><a href="https://www.eclipse.org/downloads/">https://www.eclipse.org/downloads/</a></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/276c4317-8401-4a32-a763-f5227b745c42/image.png" alt="">
링크에 접속하면 바로 다운로드 할 수 있도록 되어 있기 때문에 위 사진의 다운로드 버튼을 눌러 이클립스를 다운로드 해줍니다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/88181670-4923-46ae-a219-d133e5954d37/image.png" alt="">
다운로드 한 이클립스 인스톨러를 실행시키면 아래와 같이 실행되게 되는데, 학교 실습에서는 웹도 다루기 때문에 두번째에 Web Developers로 다운로드 해줍니다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/f3b07b5e-c619-4f4f-afd2-4a8086355a51/image.png" alt="">
파일 위치를 찾을 수 있다면 기본 위치에 설치해도 상관 없지만 저는 Java폴더에 위치시켜주었습니다. INSTALL을 클릭하면 창이 하나 뜨는데 Accept All을 눌러줍니다.
<img src="https://velog.velcdn.com/images/j_jeong2/post/6eccef6b-22df-443e-90ad-0bcbf32ec464/image.png" alt="">
런처를 누르고 워크스페이스의 위치를 지정해줍니다.</p>
<h1 id="아파치-톰캣-90-다운로드">아파치 톰캣 9.0 다운로드</h1>
<blockquote>
<p><a href="https://tomcat.apache.org/download-90.cgi">https://tomcat.apache.org/download-90.cgi</a></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/45eb28e4-f285-46ab-9529-74a37a161a4c/image.png" alt="">
아파치 톰캣에 들어간 후 왼쪽 Download에서 Tomcat 9를 찾습니다. Binary Distribution에서 Core 옵션의 32-bit/64-bit Widnows Service Installer를 다운받아줍니다.</p>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/1342e1b8-a278-470d-92fc-2cabe33e5f3e/image.png" alt="">
전체 컴포넌트를 받아줍니다.</p>
<p><img src="https://velog.velcdn.com/images/j_jeong2/post/31f9dc0e-04d7-4cb5-83ff-2e31b7faccfc/image.png" alt="">
서버 포트는 8005, HTTP 포트는 80, User Name은 admin, password는 취향껏 기억할만한 번호로 입력하면 됩니다.</p>
]]></description>
        </item>
    </channel>
</rss>