<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>_error.log</title>
        <link>https://velog.io/</link>
        <description>Ader_Error</description>
        <lastBuildDate>Thu, 23 Jan 2025 03:50:27 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>_error.log</title>
            <url>https://velog.velcdn.com/images/_error/profile/46c2e408-fd23-4f59-8631-d9847d41a602/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. _error.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/_error" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Spring Framework]]></title>
            <link>https://velog.io/@_error/Spring-Framework</link>
            <guid>https://velog.io/@_error/Spring-Framework</guid>
            <pubDate>Thu, 23 Jan 2025 03:50:27 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>Spring Framework</strong> 는 엔터프라이즈 애플리케이션 개발을 위한 포괄적인 프로그래밍과 구성 모델을 제공하는 자바 기반의 프레임워크로, 어떤 종류의 배포 플랫폼에서도 적용이 가능합니다.
스프링은 애플리케이션 수준에서의 인프라 지원으로, 특정 배포 환경에 불필요하게 얽히지 않고, 애플리케이션 수준의 비즈니스 로직에 집중할 수 있도록 도움을 준다.</p>
</blockquote>
<h2 id="스프링-프레임워크의-핵심-기술">스프링 프레임워크의 핵심 기술</h2>
<p><strong>IOC(Inversion of Control) = 제어의 역전</strong></p>
<ul>
<li>객체의 생명 주기(생성, 초기화, 소멸, 호출 등)을 개발자가 결정하는 것이 아니라, 스프링 프레임워크가 객체의 생명 주기를 관리</li>
</ul>
<p><strong>DI(Dependency Injection) = 의존성 주입</strong></p>
<ul>
<li>A객체와 B객체가 관계가 있는 경우, 스프링 컨테이너가 의존성을 주입하여,
개발자가 코드 상에서 객체의 생성과 관계에 대해 관여하지 않아도 되기 때문에, 객체의 의존도와 겹합도를 낮추고 유연성을 확보할 수 있다.</li>
</ul>
<p>** AOP(Aspect Oriented Programming) = 관점 지향 프로그래밍**</p>
<ul>
<li>핵심 로직과는 별도로 부가적인 기능(로깅, 트랜잭션, 예외처리, 보안 등)을 모듈화하여 관리할 수 있게 해주는 프로그래밍 기법.</li>
</ul>
<hr>
<h2 id="스프링이-객체를-관리하는-방법">스프링이 객체를 관리하는 방법</h2>
<p>** 스프링 컨테이너**</p>
<p><img src="https://velog.velcdn.com/images/_error/post/531f9e3d-4266-43a4-9e27-7df16907f88d/image.png" alt="">
스프링 컨테이너는 <strong>BeanFactory</strong> 와 <strong>ApplicationContext</strong> 두 종류의 인터페이스로 구현되어 있다.</p>
<ul>
<li><p><strong>BeanFactory</strong>
스프링의 가장 기본적인 IoC 컨테이너로, 객체(Bean)의 라이프사이클(초기화, 소멸 등)과 의존성을 주입, 지연 로딩(Lazy Loading) 방식으로 동작하며, 임베디드 시스템이나 매우 간단한 테스트 환경에서 주로 사용된다.</p>
</li>
<li><p><strong>ApplicationContext</strong>
BeanFactory를 확장한 인터페이스로, 더 많은 고급 기능(국제화, 이벤트 처리, AOP, 트랜잭션, 환경 설정 등)을 제공, 즉시 로딩(Eager Loading) 방식으로 동작하며, 대규모 엔터프라이즈 애플리케이션이나 복잡한 기능을 요구하는 경우 사용된다.</p>
</li>
</ul>
<hr>
<h2 id="스프링-프레임워크로-객체-관리하기">스프링 프레임워크로 객체 관리하기</h2>
<h3 id="스프링-어노테이션">스프링 어노테이션</h3>
<ul>
<li>스프링 프레임워크에서 <strong>어노테이션은 클래스, 메서드, 필드, 매개변수 등에 메타데이터를 제공하는 마킹 기능</strong>으로 <strong>어노테이션을 사용함으로써 코드에 부가적인 정보나 설정을 주입할 수 있으며</strong>, 코드 간결화, 가독성 향상, 유지보수성, 개발 생산성이 증가한다. 스프링에서 어노테이션은 <code>@[어노테이션명]</code> 으로 사용된다.
<img src="https://velog.velcdn.com/images/_error/post/80c85765-5321-466c-a9a9-9312d6804a9f/image.png" alt=""></li>
</ul>
<p>객체를 관리하는데에는 결합도에 따라 Java Bean, POJO(Plain Old Java Object), Spring Bean 으로 나눌 수 있지만 스프링 컨테이너가 관리하는 모든 객체는 Spring Bean으로 <code>new</code> 를 사용하여 생성된 것이 아니라, 스프링에 의해 생성되고 관리된다.</p>
<hr>
<h2 id="스프링-프레임워크의-의존성-관리">스프링 프레임워크의 의존성 관리</h2>
<p>스프링 프레임워크를 사용하면 객체가 아닌 의존성과 와이어링에 집중할 수 있다. 개발자는 애플리케이션의 비즈니스 로직에 집중할 수 있고, 스프링 프레임워크는 객체의 생명 주기를 관리하므로, @Component, @Autowired 어노테이션을 사용해서 의존성을 표시하기만 하면 된다.
그러면 스프링 프레임워크는 우리를 위해 전체 시스템의 준비를 갖춘다.</p>
<p><img src="https://velog.velcdn.com/images/_error/post/0be0ad39-0b38-4129-b738-8902e3d0b9eb/image.png" alt=""></p>
<p>스프링 프레임워크가 객체를 관리해주지만 스프링의 기본 객체 로딩 방식은 즉시 로딩이다.
스프링 컨테이너는 애플리케이션이 시작될 때 객체(Bean)를 생성하고 로딩 시점을 신경 쓸 필요가 없기 때문에, 코드를 단순하게 작성할 수 있지만, 애플리케이션 실행 시점에 모두 생성되기 때문에, 초기 성능이 저하될 수 있다. 따라서 특정 요청에서만 사용되는 객체는 지연 로딩을 사용하는 것이 최적화에 좋다.</p>
<p><strong>지연 로딩(Lazy Loading)</strong>은 스프링 컨테이너가 객체(Bean)가 필요한 시점에 로딩하는 방식이다. 초기 성능을 향상시키고 리소스를 절약할 수 있는 장점이 있지만, 로딩 시점이 애플리케이션이 실행된 이후(Runtime)이므로, 예상치 못한 문제를 유발할 수 있고, 디버깅이 어려운 문제가 있으니, 특정 상황에 맞게 주의하여 사용하는 것이 좋다.</p>
<p><img src="https://velog.velcdn.com/images/_error/post/0f475064-48e0-4b57-b88a-fd8ec5d5d4ea/image.png" alt=""></p>
<hr>
<h2 id="spring-bean-scope">Spring Bean Scope</h2>
<p>스프링에서 객체의 생성과 소멸의 범위를 개발자는 간단하게 어노테이션으로 관리할 수 있다.
@Scope(”singletin”) 또는 생략 --- 스프링 컨테이너 당 하나의 인스턴스
@Scope(”prototype”) --- 요청할 때마다 새로운 인스턴스
@Scope(”request”) --- HTTP 요청 당 하나의 인스턴스
@Scope(”session”) --- HTTP 세션 당 하나의 인스턴스
@Scope(”application”) --- 애플리케이션 범위에서 하나의 인스턴스
@Scope(”websocket”) --- 웹 소켓 연결 당 하나의 인스턴스</p>
<hr>
<h2 id="스테레오타입-어노테이션">스테레오타입 어노테이션</h2>
<ul>
<li>객체(Bean)를 정의하기 위해 <code>@component</code> 어노테이션을 사용하였지만 이를 더욱 명확하게하여
유지보수 및 가독성을 높일 수 있다. 물론 <code>@component</code>으로 모든 클래스에 정의내려 쓸 수 있지만 각 클래스들이 무슨 역할을 하는지 의도를 명확하게 파악하기 어려워진다.
<img src="https://velog.velcdn.com/images/_error/post/8583618a-fbb7-4fcf-a5fb-30ebc4ef08c7/image.png" alt=""></li>
</ul>
<h2 id="스테레오타입-어노테이션-종류">스테레오타입 어노테이션 종류</h2>
<p><span color="1e2e2"><em>(스테레오타입 어노테이션은 @Component 어노테이션을 기본으로 하여, 플리케이션 구조를 명확하게 하기 위해 파생된 어노테이션이다)</em></span></p>
<h3 id="controller">@Controller</h3>
<p>해당 클래스가 웹 요청을 처리하는 컨트롤러임을 나타내며, MVC 패턴의 컨트롤러 역할을 수행하고, 이 어노테이션이 붙은 객체는 <strong>DispatcherServlet</strong> 이 핸들링 하는 객체가 되며, 뷰를 반환하거나, Restful API의 엔드포인트로 동작한다.</p>
<h3 id="service">@Service</h3>
<p>해당 클래스가 비즈니스 로직을 처리하는 클래스임을 나타냄
애플리케이션의 비즈니스 로직, 트랜잭션, Presentation 레이어와 Data Access 레이어의 중간다리 역할 등을 수행.</p>
<h3 id="repository">@Repository</h3>
<p>해당 클래스가 데이터 접근 객체(Data Access Obejct)임을 나타냄.
데이터베이스, 파일 시스템, 3rd-party 등 데이터 저장소와 통신하는 역할을 수행.</p>
<h3 id="configuration">@Configuration</h3>
<p>해당 클래스가 스프링 설정 정보를 담고있는 객체임을 나타냅니다.
@Bean 어노테이션으로 애플리케이션에 필요한 설정 객체를 등록할 수 있습니다(데이터베이스 연결 설정, 3rd-party 설정 등).</p>
<hr>
<h2 id="함수형-프로그래밍">함수형 프로그래밍</h2>
<p>함수형 프로그래밍은 자료 처리를 수학적 함수의 계산으로 취급하고,
상태와 가변 데이터를 멀리하는 프로그래밍 패터다임의 하나. 함수형 프로그래밍은 병렬 처리에 유리하여 2010년, 빅데이터와 분산 시스템이 발전하면서 많은 인기를 얻기 시작했다. 현재 많은 프로그래밍 언어들이 함수형을 지원하고 있으며, 자바는 8버전 이후부터 람다 표현식(Lambda Expression) 과 Stream API 가 도입되어 함수형 프로그래밍을 작성할 수 있게 되었되었다.</p>
<p>###</p>
<p>람다 표현식(Lambda Expression)</p>
<p>함수형 프로그래밍을 구성하기 위한 함수식을 말합니다.
메서드를 하나의 식으로 표현한 것으로, 익명 함수(Anonymous Function)입니다.
<strong>자바에서 람다 표현식은 화살표로 표현</strong>합니다.</p>
<pre><code class="language-java">(int a, int b) -&gt; { 
    int result = a * b; 
    return result; 
}</code></pre>
<h3 id="명령형과-선언형-프로그래밍">명령형과 선언형 프로그래밍</h3>
<ul>
<li><strong>명령형 프로그래밍</strong></li>
</ul>
<p><strong>어떻게(How)</strong> 문제를 해결할지를 기술하는 방식입니다.
명령어가 순차적으로 실행되며, 조건문, 반복문 등의 <strong>실행 흐름을 명시적으로 정의</strong>합니다.
<strong>프로그램이 실행됨에 따라 변수를 변경 또는 데이터 상태가 변하는 방식</strong>으로 동작합니다.</p>
<pre><code class="language-java">int[] numbers = {1, 2, 3, 4, 5};
for (int i = 0; i &lt; numbers.length; i++) {
    numbers[i] = numbers[i] * 2;
}</code></pre>
<ul>
<li><strong>선언형 프로그래밍</strong></li>
</ul>
<p><strong>무엇을(What)</strong> 해결할지를 기술하는 방식입니다.
결과를 정의하는 데 중점을 두며, <strong>실행 흐름을 직접적으로 명시하지 않습니다.</strong></p>
<pre><code class="language-java">int[] numbers = {1, 2, 3, 4, 5};
int[] doubledNumbers = Arrays.stream(numbers).map(n -&gt; n * 2).toArray();
// 어떻게 map 함수가 내부적으로 동작하는지 신경쓰지 않고, 해당 배열의 요소를 2배로 만들겠다는 결과만 정의</code></pre>
<hr>
<h2 id="스프링-부트-시작하기">스프링 부트 시작하기</h2>
<ul>
<li>스프링 부트는 대부분의 설정을 자동으로 처리하여 초기 설정의 복잡함을 줄이고,
의존성 관리를 간소화하여 버전 관리와 호환성 문제를 해결하고 배포를 위한 내장 웹 서버(Tomcat, Jetty, Undertow 등)도 가지고 있어, 외부 웹 서버 필요 없이 독립적으로 실행할 수 있게 되었다.</li>
</ul>
<p><strong>📁 src/main/java</strong>
Java 소스 코드가 위치하는 디렉토리.</p>
<p><strong>📁 src/main/resources</strong>
애플리케이션 리소스 파일들(설정 파일, 정적 파일, 뷰 템플릿)이 위치하는 디렉토리.</p>
<p><strong>📁 static</strong>
HTML, CSS, JS, 이미지 같은 정적 리소스 파일이 위치하는 디렉토리입니다. 이곳에 위치한 파일들은 /static 경로 없이 제공</p>
<p><strong>📁 templates</strong>
Thymeleaf, Freemarker, Mustache 와 같은 서버 사이드 템플릿 파일을 저장하는 디렉토리.</p>
<p><strong>📁 src/test/java</strong>
테스트 코드가 위치하는 디렉토리 입니다. <code>JUnit</code>, <code>Mockito</code> 등을 활용하여 테스트 코드를 작성할 수 있다.</p>
<p><strong>📄 application.properties / application.yml</strong>
애플리케이션 환경 설정 파일입니다. 데이터베이스, 포트, 로깅 등 다양한 설정을 이 곳에서 정의할 수 있다.</p>
<p><strong>📄 pom.xml (Maven) / build.gradle (Gradle)</strong>
Maven 프로젝트, Gradle 프로젝트에 따라 생성되는 프로젝트 빌드 설정 파일입니다.
의존성 관리와 빌드 설정을 정의하는 데 사용.</p>
<hr>
<h2 id="jdbc-이해하기">JDBC 이해하기</h2>
<p>Java DataBase Connectivity 의 약자로, 자바에서 데이터베이스에 접속할 수 있도록 하는 표준화된 API를 말한다. JDBC는 JDK1.1 버전에 출시된 아주 오래된 기술이며, 요즘은 직접 사용하는 일은 거의 없고, JDBC를 기반으로 동작하는 기술들(Spring JDBC, Hibernate, Spring Data JPA, MyBatis 등)을 사용하고 있다.</p>
<h3 id="mybatis">MyBatis</h3>
<p>MyBatis는 SQL을 직접 작성할 수 있도록 지원하는 SQL 기반의 프레임워크입니다. 기존 JDBC의 불편함을 해결하면서도, SQL의 강력한 제어를 유지할 수 있다.</p>
<h3 id="jpa">JPA</h3>
<p>JPA(Java Persistence API)는 자바의 표준 ORM(객체-관계 매핑) 프레임워크로, SQL을 직접 작성하지 않고 객체 중심적인 방식으로 데이터베이스 작업을 수행한다.</p>
<hr>
<h2 id="mvc-디자인-패턴과-dispatcher-servlet">MVC 디자인 패턴과 Dispatcher Servlet</h2>
<p><img src="https://velog.velcdn.com/images/_error/post/62fd4932-07a2-4864-8b9b-25582e12915a/image.png" alt=""></p>
<p>모든 흐름의 제어는 Front Controller 가 담당하고, 일부 로직은 컨트롤러가
처리하도록 위임(Delegation)하는 구조가 특징이며, Spring MVC의 아키텍처이다.</p>
<p>💡<strong>Dispatcher Servlet</strong></p>
<p>Spring MVC 에서 핵심적인 역할을 하는 서블릿으로, 모든 웹 요청은 Dispatcher Servlet 을 통해 처리되고 라이언트 요청을 컨트롤러로 전달하고, 결과를 View 로 반환하는 일을 수행한다.</p>
<hr>
<h2 id="http-status-codes">HTTP Status Codes</h2>
<ul>
<li><strong>1xx: Informational</strong>
100 Continue → 임시 응답으로, 지금까지 상태가 괜찮으니 클라이언트가 계속해서 요청을 하거나, 요청을 완료한 경우 무시해도 되는 것을 알려줍니다.
101 Switching Protocal → 클라이언트 요청에 따라 서버에서 프로토콜을 변경할 것임을 알려줍니다.</li>
<li><strong>2xx: Success</strong>
200 OK → 요청이 성공적으로 처리되었음을 알려줍니다.
201 Created → 요청이 성공했고, 새로운 리소스가 생성됐음을 알려줍니다.
202 Accepted → 요청을 수락했으나, 아직 처리가 완료되지 않음을 알려줍니다.
204 No Content →요청은 성공했으나 보내줄 수 있는 리소스가 없음을 알려줍니다. <code>PUT</code> 결과가 없는 경우 204 상태를 반환합니다.</li>
<li><strong>3xx: Redirectional</strong>
300 Multiple Choices → 요청한 리소스에 하나 이상의 응답이 가능함을 알려줍니다.
301 Moved Permanently → 요청한 리소스가 다른 URI로 변경되었음을 알려줍니다.
302 Found → 요청한 리소스가 일시적으로 URI가 변경되었음을 알려줍니다.
303 See Other → 요청한 리소스는 다른 URI에서 확인할 수 있음을 알려줍니다.
304 Not Modified → 캐시 목적으로 사용되며, 응답이 수정되지 않았음을 알려줍니다.</li>
<li><strong>4xx: Client Error</strong>
400 Bad Request → 잘못된 요청 형식임을 알려줍니다. 서버가 요구하는 리소스 형식에 맞지 않는 경우에 발생합니다.
401 Unauthorized → 인증이 필요하거나, 인증이 실패했음을 알려줍니다.
403 Forbidden → 리소스에 접근할 권한을 가지고 있지 않음을 알려줍니다.
404 Not Found → 요청한 리소스를 찾을 수 없음을 알려줍니다.
405 Method Not Allowed → 요청된 HTTP 메서드가 허용되지 않음을 알려줍니다.
409 Conflict → 클라이언트 요청이 서버의 현재 상태와 충돌(리소스 중복, 버전 충돌 등)이 발생했음을 알려줍니다.</li>
<li><strong>5xx: Server Error</strong>
500 Internal Server Error → 서버에 오류가 발생했음을 알려줍니다. 
501 Not Implemented → 요청한 기능이 서버에서 지원하지 않음을 알려줍니다.
502 Bad Gateway → 게이트웨이, 프록시 서버가 잘못된 응답을 수신했음을 알려줍니다.
503 Service Unavailable → 서버 과부화 또는 유지보수 중으로 현재 요청을 처리할 수 없음을 알려줍니다.
504 Gateway Timeout → 게이트웨이가 요청을 처리하는데 시간이 초과됐음을 알려줍니다.</li>
</ul>
<p>-- </p>
<h2 id="스프링-restapi-개발하기">스프링 RestAPI 개발하기</h2>
<p><strong>REST API란?</strong></p>
<ul>
<li>REST API는 API의 한 종류로, REST(Representational State Transfer) 아키텍처 스타일을 따르는 웹 API 즉, HTTP 프로토콜을 기반으로 리소스를 정의하고 조작하는 방식</li>
</ul>
<p>( HTTP : Hyper Text Transfer Protocal 의 약자로, 웹에서 클라이언트와 서버 간 데이터를 주고받기  위한 통신 규약)</p>
<p>RestAPI 를 설계할 때 유용한 어노테이션</p>
<h3 id="pathvariable-requestparam-requestbody">@PathVariable, @RequestParam, @RequestBody</h3>
<p><code>@PatiVariable</code></p>
<p>URL 경로에 있는 변수를 메서드 파라미터로 바인딩할 수 있습니다.</p>
<pre><code class="language-java">@RestController
public class UserController {
        // http://localhost:8080/users/james
    @GetMapping(&quot;/users/{id}&quot;)
    public ResponseEntity&lt;String&gt; getUserById(@PathVariable String id) {
        return ResponseEntity.ok(&quot;User ID: &quot; + id);
    }
}</code></pre>
<p><code>@RequestParam</code>
쿼리 스트링 또는 폼 데이터에 있는 요청 파라미터를 메서드 파라미터로 바인딩할 수 있습니다.</p>
<pre><code class="language-java">@RestController
public class SearchController {

    // http://localhost:8080/search?keyword=foo
    @GetMapping(&quot;/search&quot;)
    public ResponseEntity&lt;String&gt; search(@RequestParam String keyword) { 
        return ResponseEntity.ok(&quot;Searching for: &quot; + keyword);
    }
}</code></pre>
<p><code>@RequestBody</code>
HTTP 본문(Body)에 있는 데이터를 메서드 파라미터로 매핑할 수 있습니다.
POST, PUT, PATCH 요청의 데이터를 객체로 변환할 때 사용됩니다.</p>
<pre><code class="language-java">@RestController
public class UserController {

        // {
        //  &quot;username&quot;: &quot;john&quot;,
        //  &quot;email&quot;: &quot;john@example.com&quot;
        // }
    @PostMapping(&quot;/users&quot;)
    public ResponseEntity&lt;String&gt; createUser(@RequestBody User user) {
        return ResponseEntity.ok(&quot;User created: &quot; + user.getUsername());
    }
}</code></pre>
<p><code>JsonIgnore</code>
해당 어노테이션이 붙은 필드는 요청/응답 데이터에서 제외시킬 수 있다.</p>
<pre><code class="language-java">import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;

import java.time.LocalDate;


@Data
public class UserDto {
    private String id;

        // 비밀번호는 응답 데이터에서 제외
    @JsonIgnore
    private String password;

    private String username;
    private int age;
    private LocalDate createdAt;
}</code></pre>
<p><code>ResponseEntity</code></p>
<p><code>HTTP Response</code> 를 표현하는데 사용하는 클래스로, 단순 객체를 <code>return</code> 하는 것 보다 <code>Header</code>, <code>Body</code>, <code>HTTP Status Code</code> 를 직접 제어할 수 있어 유용하다.</p>
<pre><code class="language-java">
import com.example.lecture014.user.dto.UserDto;
import com.example.lecture014.user.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List

@RestController
@RequiredArgsConstructor
@RequestMapping(&quot;/api/v1&quot;)
public class UserController {
    private final UserService userService;

    @GetMapping(&quot;/users&quot;)
    public ResponseEntity&lt;List&lt;UserDto&gt;&gt; getAllUsers() {
        return ResponseEntity.ok(userService.getAllUsers());
    }
}</code></pre>
<p><strong>RestAPI 예시 시나리오</strong></p>
<p><img src="https://velog.velcdn.com/images/_error/post/9358c42a-0c10-4017-97ff-c25ce2da4d69/image.png" alt=""></p>
<p><em>💡Resource 가 같아도 HTTP Method 가 다르면  같은 API가 아니다.</em></p>
<hr>
<h2 id="데이터-유효성-검증하기">데이터 유효성 검증하기</h2>
<p> Rest API 의 POST, PUT, PATCH 요청에 포함된 데이터가 유효한 값인지 검증하는 로직이 없을 경우 <code>spring-boot-starter-validation</code> 을 사용하여 데이터 유효성 검증을 통해 올바른 요청을 했는지 확인할 수 있다.</p>
<p>  <strong><code>Validation Annotations 간단정리</code></strong></p>
<ul>
<li><strong><code>@Valid</code></strong>
선언된 매개 변수/객체에 대한 검증을 자동으로 트리거한다.</li>
</ul>
<ul>
<li><p><strong><code>@Validated</code></strong>
선언된 매개 변수/객체에 대한 검증을 자동으로 트리거하는데,
검증 그룹을 지정할 수 있다.</p>
</li>
<li><p><strong><code>@NotNull</code></strong>
값이 <code>null</code> 이 아니여야 한다.</p>
</li>
<li><p><strong><code>@Null</code></strong>
값이 <code>null</code> 이여야 한다.</p>
</li>
<li><p><strong><code>@Min(value)</code>, <code>@Max(value)</code></strong>
  숫자의 최소/최대 값을 제한한다.</p>
</li>
<li><p><strong><code>@Size(min, max)</code></strong>
문자열, 배열, 컬렉션의 크기의 범위를 제한한다.</p>
</li>
<li><p><strong><code>@Pattern(regex)</code></strong>
정규식을 사용하여 문자열 패턴을 검증한다.</p>
</li>
<li><p><strong><code>@Email</code></strong>
값이 이메일 형식이여야 한다.</p>
</li>
<li><p><strong><code>@Positive</code>, <code>@Negative</code></strong>
값이 양수/음수여야 한다.</p>
</li>
<li><p><strong><code>@Digits(integer, fraction)</code></strong>
소수점 자릿수나 정수부 자릴수를 제한한다.</p>
</li>
<li><p><strong><code>@Past</code>, <code>@Future</code></strong>
값이 현재 날짜보다 이전/미래여야 한다.</p>
</li>
<li><p><strong><code>@AssertTrue</code>, <code>@AssertFalse</code></strong>
값이 true/false 여야 한다.</p>
</li>
</ul>
<pre><code class="language-java">import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.Size;
import lombok.Data;


@Data
public class CreateUserDto {
    @NotNull
    @Size(max = 20)
    private String id;

    @NotNull
    @Size(max = 128)
    private String password;

    @NotNull
    @Size(max = 50)
    private String username;

    @NotNull
    @Positive
    private int age;
}
</code></pre>
<hr>
<h2 id="mybatis-resultmap">Mybatis ResultMap</h2>
<p>Mybatis 의 기본적인 자동 매핑 기능으로 처리가 어려울 때, 복잡한 결과를 매핑할 때, 다양한 매핑 요구 사항을 처리할 때, ResultMap 을 사용하여 유연하게 처리할 수 있다.
<strong>객체 필드와 데이터베이스 컬럼 이름이 다른 경우 매핑.</strong>
Mybatis 는 기본적으로 SQL 결과의 컬럼과 동일한 객체 필드에 자동으로 매핑해준다.
그러나 컬럼 이름이 객체 필드와 다를 때 자동 매핑이 불가하므로, ResultMap 을 사용하면 좋다.</p>
<pre><code class="language-java">@Data
class UserDto {
    private String userId;
    private String userName;
    private int userAge;
}
//객체 필드와 DB 컬럼이 다른 경우</code></pre>
<pre><code class="language-xml">
&lt;resultMap id=&quot;userResultMap&quot; type=&quot;com.example.dto.UserDto&quot;&gt;
    &lt;id property=&quot;userId&quot; column=&quot;id&quot;/&gt;
    &lt;result property=&quot;userName&quot; column=&quot;username&quot;/&gt;
    &lt;result property=&quot;userAge&quot; column=&quot;age&quot;/&gt;
&lt;/resultMap&gt;

&lt;select id=&quot;selectUser&quot; resultMap=&quot;userResultMap&quot;&gt;
    SELECT id, username, age FROM users WHERE id = #{id}
&lt;/select&gt;
</code></pre>
<p><em>💡객체 필드와 DB 컬럼이 다른 경우, SQL 을 작성할 때, 컬럼에 Alias 를 지정해서 조회한다면, ResultMap 을 사용하지 않아도 구현이 가능합니다.</em></p>
<hr>
<h2 id="pagination-이해하기">Pagination 이해하기</h2>
<p>만약 A 라는 사용자의 게시물이 수천, 수만 건까지 쌓여있을 경우, API가 모든 데이터를 응답한다면 성능 이슈가 발생할 수 있다. 이를 Pagination 처리를 통해 데이터를 잘라서 보낼 수 있도록 한다.</p>
<h3 id="pagination-로직">Pagination 로직</h3>
<p>페이징 처리의 핵심은 데이터를 어느 위치에서부터 가져올지를 구하는 것</p>
<pre><code class="language-java">offset = (page - 1) * size

예시) page=2, size=10 인 경우, offset 은 (2 - 1) * 10 = 10 이 되며, DB에서는 11번째 데이터부터 가져오게 됩니다.</code></pre>
<h3 id="pagination-쿼리-예시오라클-기준">Pagination 쿼리 예시(오라클 기준)</h3>
<pre><code class="language-sql">SELECT 
    T.*
FROM (
    SELECT
        ROW_NUMBER() OVER (ORDER BY order_column ASC) ROW_NUM,
        *
    FROM table_name
) T
WHERE ROW_NUM &gt;= #{offset} AND ROW_NUM &lt;= #{offset} + #{size}</code></pre>
<p>방식1: 전통적인 방법</p>
<pre><code class="language-sql">SELECT *
FROM table_name
ORDER BY order_column
OFFSET #{offset} ROWS FETCH NEXT #{size} ROWS ONLY;</code></pre>
<p>방식2: Oracle 12c 버전 이상</p>
<p><em>💡OFFSET FETCH 를 사용하면 쿼리가 간결하지만, 레코드를 많이 건너뛸수록(페이지가 커질수록) 성능이 저하될 수 있다.</em></p>
<hr>
<h2 id="aopaspect-oriented-programming">AOP(Aspect-Oriented Programming)</h2>
<p>관점 지향 프로그래밍(Aspect-Oriented Programming)이란, <strong>핵심 기능과는 별도로 분리된 관심사를 모듈화하여 코드 중복을 줄이고, 유지보수성을 높이는 프로그래밍 패러다임</strong> 로깅, 보안, 트랜잭션 등 비즈니스 로직에서 부가적인 기능을 분리하는데 중점을 둔다.</p>
<p>대표적인 자바기반 AOP 프레임워크</p>
<ul>
<li><h3 id="spring-aop">Spring AOP</h3>
</li>
</ul>
<p>스프링 프레임워크에서 제공하는 경량 AOP 프레임워크로, 가장 인기가 많다.
<strong>프록시(Proxy) 패턴</strong>으로 AOP를 구현하며, <strong>스프링 빈(Bean)을 대상으로만 AOP 기능을 제공</strong>하므로, 완전한 AOP 솔루션이라고 말할 수 없다.</p>
<ul>
<li><h3 id="aspect-j">Aspect J</h3>
스프링 AOP보다 더 강력하고 완전한 AOP 프레임워크지만, 거의 사용되지 않는다.
자바 언어 수준에서 직접 AOP를 구현할 수 있고, 모든 자바 객체에 AOP를 적용할 수 있다.
AOP를 구현하기에 강력한 프레임워크지만, 설정이 복잡하고 비교적 무거운 프레임워크다.</li>
</ul>
<hr>
<h2 id="트랜잭션transaction">트랜잭션(Transaction)</h2>
<p>트랜잭션(Transaction)이란, <strong>데이터베이스나 시스템에서 하나의 작업 단위를 의미하는데,
그 작업이 완전히 성공하거나, 완전히 실패하여 원래 상태로 돌아가야 하는 특성을 가진다</strong>
데이터의 일관성을 보장하기 위해 트랜잭션은 반드시 필요하며, 여러 작업을 하나로 묶어서 처리할 때 사용.</p>
<h3 id="주요-속성acid">주요 속성(ACID)</h3>
<ul>
<li><strong>원자성(Atomicity)</strong>
트랜잭션 내 모든 작업은 전부 성공하거나 실패해야 합니다(일부만 실행될 수 없음).</li>
<li><strong>일관성(Consistency)</strong>
트랜잭션이 실행되기 전/후에 시스템은 항상 일관된 상태를 유지해야 합니다(트랜잭션 중간에 데이터가 불일치하면 안됨).</li>
<li><strong>고립성(Isolation)</strong>
동시에 여러 트랜잭션이 실행되어도 각 트랜잭션은 독립적으로 실행되어야 합니다(트랜잭션의 중간 결과를 다른 트랙잭션이 참조하면 안됨).</li>
<li><strong>지속성(Durability)</strong>
트랜잭션이 성공했다면, 그 결과는 시스템에 반영되어 오류나 장애가 발생해도 유지되어야 합니다.</li>
</ul>
<h3 id="처리-흐름">처리 흐름</h3>
<ul>
<li><strong>BEGIN</strong>
트랜잭션 시작을 알립니다.</li>
<li><strong>COMMIT</strong>
트랜잭션이 성공했을 때, 변경된 사항을 확정하고 반영합니다.</li>
<li><strong>ROLLBACK</strong>
트랜잭션이 실패했을 때, 변경된 사항을 이전 상태로 되돌립니다.</li>
</ul>
<p><code>@Transactional</code></p>
<p>스프링 프레임워크에서 제공하는 어노테이션으로, <strong>메서드 또는 클래스 수준에서 트랜잭션 처리를 설정</strong>할 수 있도록 해준다.
어노테이션된 메서드 또는 클래스는 하나의 트랙잭션으로 처리되며, ACID 속성을 보장할 수 있다.</p>
<p>만약 <code>@Transactional</code>을 사용하지 않는다면?</p>
<pre><code class="language-java">import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class BankService {

    public void transferMoney(long fromAccountId, long toAccountId, double amount) {
        Connection connection = null;

        try {
            // 1. 데이터베이스 연결
            connection = DriverManager.getConnection(&quot;jdbc:mysql://localhost:3306/mydb&quot;, &quot;user&quot;, &quot;password&quot;);

            // 2. 트랜잭션 시작
            connection.setAutoCommit(false);

            // 3. A 계좌에서 출금
            try (PreparedStatement withdrawStmt = connection.prepareStatement(
                    &quot;UPDATE account SET balance = balance - ? WHERE id = ?&quot;)) {
                withdrawStmt.setDouble(1, amount);
                withdrawStmt.setLong(2, fromAccountId);
                withdrawStmt.executeUpdate();
            }

            // 4. B 계좌에 입금
            try (PreparedStatement depositStmt = connection.prepareStatement(
                    &quot;UPDATE account SET balance = balance + ? WHERE id = ?&quot;)) {
                depositStmt.setDouble(1, amount);
                depositStmt.setLong(2, toAccountId);
                depositStmt.executeUpdate();
            }

            // 5. 트랜잭션 커밋
            connection.commit();
        } catch (SQLException e) {
            // 6. 오류 발생 시 롤백
            if (connection != null) {
                try {
                    connection.rollback();
                } catch (SQLException rollbackEx) {
                    rollbackEx.printStackTrace();
                }
            }
            e.printStackTrace();
        } finally {
            // 7. 연결 닫기
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException closeEx) {
                    closeEx.printStackTrace();
                }
            }
        }
    }
}</code></pre>
<p>그렇다면 <code>@Transactional</code>을 사용하기 위해 <code>@Transactional</code>의 주요 속성을 알아보자.</p>
<ul>
<li>propagation
현재 트랜잭션이 이미 존재하는지 여부에 따라 새로운 트랜잭션을 생성할지, 아니면 참여할지 결정한다.
<img src="https://velog.velcdn.com/images/_error/post/621580e7-6663-4c07-9c05-31cee70b8862/image.png" alt=""></li>
</ul>
<ul>
<li>Isolation
트랜잭션 격리 수준을 설정하며, 동시성 문제를 어떻게 처리할지 결정한다.
<img src="https://velog.velcdn.com/images/_error/post/c26eb5f8-d190-456d-8139-93758570c31c/image.png" alt=""></li>
</ul>
<hr>
<h2 id="파일-업로드다운로드-기능-구현하기">파일 업로드/다운로드 기능 구현하기</h2>
<p><a href="https://henrykim90.notion.site/018-12620a7966e780ecb7b0d1d2df180663">https://henrykim90.notion.site/018-12620a7966e780ecb7b0d1d2df180663</a></p>
<hr>
<h3 id="spring-security">Spring Security</h3>
<p>스프링 기반 웹 애플리케이션, REST API 개발 시 인증(Authentication)과 권한 부여(Authorization) 기능을 제공하는 보안 프레임워크로Spring Security 는 URL 및 메서드 단위로 접근을 제어할 수 있으며, 다양한 인증 및 권한 부여 방식(OAuth2, LDAP, JWT 등)을 지원하고, 요청이 애플리케이션 리소스에 접근하기 전에 여러 보안 필터를 통과하도록 할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/_error/post/d584b9a4-3696-4506-8bdb-eac34f8fbfcc/image.png" alt=""></p>
<h3 id="주요-보안-원칙">주요 보안 원칙</h3>
<ol>
<li>아무것도 신뢰하지 말고, 들어오는 <strong>모든 요청을 검증</strong>해야 한다.</li>
<li>시스템 설계를 시작할 때부터 보안을 염두하여 설계하고,  <strong>사용자나 시스템이 필요한 최소한의 권한만을 부여</strong>받도록 해야한다.</li>
<li>모든 사람이 통과하는 문은 하나여야 합니다. <code>Spring Security Filter Chain</code> 이 문(Door) 역할을 수행할 수 있다.</li>
<li><strong>심층적인 방어구조를 설계</strong>해야 합니다. 단일 보안 계층에 의존하지 않고, 공격자가 시스템에 침투하는 것을 어렵게 만들어야 한다(전송 레이어, 네트워크 레이어,  운영체제 레벨 등 심층적으로 보안을 구현).</li>
<li><strong>보안 아키텍쳐를 가능한 간단하게 설계/유지</strong>하는 것이 좋습니다. 시스템이 단순할수록 설계자가 의도한 대로 공격자가 행동할 가능성이 높아지고, 반대로 복잡한 시스템은 공격 표면이 넓어져 취약점이 많아질 수 있다.</li>
<li>개방형 보안 설계를 구축하고, <strong>개방형 보안 표준(OAuth, JWT, TLS 등)을 사용</strong>하세요. 표준화된 프로토콜 및 인증 방식이 아닌, 독자적인 보안 방식은 보안성, 호환성, 개발 속도 저하 등 다양한 문제가 발생할 수 있다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] 배열에서 사용가능한 메서드 5종]]></title>
            <link>https://velog.io/@_error/javascript-%EB%B0%B0%EC%97%B4%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%EA%B0%80%EB%8A%A5%ED%95%9C-%EB%A9%94%EC%84%9C%EB%93%9C-5%EC%A2%85</link>
            <guid>https://velog.io/@_error/javascript-%EB%B0%B0%EC%97%B4%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%EA%B0%80%EB%8A%A5%ED%95%9C-%EB%A9%94%EC%84%9C%EB%93%9C-5%EC%A2%85</guid>
            <pubDate>Thu, 16 Jan 2025 03:21:25 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><code>forEach</code> <code>includes</code> <code>indexOf</code> <code>findIndex</code> <code>find</code></p>
</blockquote>
<hr>
<h3 id="foreach">forEach</h3>
<pre><code class="language-javascript">const numbers = [1, 2, 3, 4, 5];
numbers.forEach((v, i) =&gt; {
    console.log(`Index: ${i}, Value: ${v}`);
});
</code></pre>
<pre><code class="language-yaml">Index: 0, Value: 1
Index: 1, Value: 2
Index: 2, Value: 3
Index: 3, Value: 4
Index: 4, Value: 5
</code></pre>
<hr>
<h3 id="includes">includes</h3>
<pre><code class="language-javascript">const fruits = [&#39;apple&#39;, &#39;banana&#39;, &#39;orange&#39;];
console.log(fruits.includes(&#39;banana&#39;));  // true
console.log(fruits.includes(&#39;grape&#39;));   // false
// 배열에 특정 값이 포함되어 있는지 여부를 확인하는 메소드, boolean 값을 반환</code></pre>
<hr>
<h3 id="indexof">indexOf</h3>
<pre><code class="language-javascript">const colors = [&#39;red&#39;, &#39;green&#39;, &#39;blue&#39;];
console.log(colors.indexOf(&#39;green&#39;));  // 1
console.log(colors.indexOf(&#39;yellow&#39;)); // -1

// 메소드는 배열에서 특정 값이 처음 등장하는 인덱스를 반환, 값이 배열에 없으면 -1을 반환.</code></pre>
<hr>
<h3 id="findindex">findIndex</h3>
<pre><code class="language-javascript">const numbers = [5, 12, 8, 130, 44];
const index = numbers.findIndex((num) =&gt; num &gt; 10);
console.log(index);  // 1 (12가 첫 번째로 10보다 큼)


// 배열에서 주어진 테스트 함수를 만족하는 첫 번째 요소의 인덱스를 반환.
// 조건을 만족하는 요소가 없으면 -1을 반환.</code></pre>
<hr>
<h3 id="find">find</h3>
<pre><code class="language-javascript">const users = [
    { name: &#39;Alice&#39;, age: 25 },
    { name: &#39;Bob&#39;, age: 30 },
    { name: &#39;Charlie&#39;, age: 35 }
];

const user = users.find((user) =&gt; user.age &gt; 30);
console.log(user);  // { name: &#39;Charlie&#39;, age: 35 }



//  배열에서 주어진 조건을 만족하는 첫 번째 요소를 반환.
// 조건을 만족하는 요소가 없으면 undefined를 반환.</code></pre>
<hr>
<p><img src="https://velog.velcdn.com/images/_error/post/4d8ca73f-230c-4237-ad53-e4bade05e56f/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript]배열 & 객체 순회 ]]></title>
            <link>https://velog.io/@_error/javascript%EB%B0%B0%EC%97%B4-%EA%B0%9D%EC%B2%B4-%EC%88%9C%ED%9A%8C</link>
            <guid>https://velog.io/@_error/javascript%EB%B0%B0%EC%97%B4-%EA%B0%9D%EC%B2%B4-%EC%88%9C%ED%9A%8C</guid>
            <pubDate>Thu, 16 Jan 2025 02:44:06 GMT</pubDate>
            <description><![CDATA[<p>배열을 순회하는 방법 중 기본 for문 외에도 더욱 쉽고 유용한 방법들이 존재한다.</p>
<blockquote>
<p><strong>배열순회</strong></p>
</blockquote>
<h4 id="11-forof-반복문-fromes6">1.1 for...of 반복문 (from.ES6)</h4>
<pre><code class="language-javascript">for (let item of arr) {
  //arr 배열을 item으로 반환
  console.log(item);
}</code></pre>
<blockquote>
<p><strong>객체순회</strong></p>
</blockquote>
<hr>
<h4 id="21-objectkeys">2.1 <code>Object.keys()</code></h4>
<pre><code class="language-javascript">let person = {
  name: &quot;이정환&quot;,
  age: 27,
  hobby: &quot;테니스&quot;,
};

let keys = Object.keys(person);
//person의 key를 추출하여 배열로 반환


for (let key of keys) {
  const value = person[key];
//반환된 key를 이용하여 person객체의 값에 접근

  console.log(key, value);
}</code></pre>
<hr>
<h4 id="22-objectvalues">2.2 Object.values()</h4>
<pre><code class="language-javascript">let values = Object.values(person);
//person 객체의 value를 추출하여 배열로 반환

for (let value of values) {
  console.log(value);
}</code></pre>
<hr>
<h4 id="23-forin-반복문">2.3 for...in 반복문</h4>
<ul>
<li>객체의 모든 열거 가능한 속성 키를 순회, 이를 통해 키와 값 모두에 접근할 수 있다.</li>
</ul>
<pre><code class="language-javascript">for (let key in person) {
  const value = person[key];
  console.log(key, value);
}</code></pre>
<p><code>for...in</code> 과 <code>Object.keys()</code> 는 둘 다 속성을 기준으로 순회하지만 <code>Object.keys()</code>는 배열을 반환하고 반환된 배열을 통해 다시 객체의 값에 접근하는 반복문이 한 번 더 사용되지만 <code>for...in</code>의 경우 한 번에 키와 값을 모두 순회 가능하다.</p>
<hr>
<p><strong>정리</strong></p>
<ul>
<li><code>Object.keys()</code>는 키 배열을 반환하고, 이 배열을 다룰 수 있는 추가적인 유연성을 제공.</li>
<li><code>for...in</code>은 배열을 반환하지 않고 객체의 키를 직접 순회하며, 간단한 반복 작업에 적합.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/_error/post/15401151-dc72-484e-bbad-82e5fa066198/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript]구조 분해 할당]]></title>
            <link>https://velog.io/@_error/JavaScript%EA%B5%AC%EC%A1%B0-%EB%B6%84%ED%95%B4-%ED%95%A0%EB%8B%B9</link>
            <guid>https://velog.io/@_error/JavaScript%EA%B5%AC%EC%A1%B0-%EB%B6%84%ED%95%B4-%ED%95%A0%EB%8B%B9</guid>
            <pubDate>Thu, 16 Jan 2025 02:15:22 GMT</pubDate>
            <description><![CDATA[<h1 id="구조분해할당이란">&gt; 구조분해할당이란?</h1>
<ul>
<li><strong>구조 분해 할당(Destructuring Assignment)</strong>은 배열과 객체에서 값을 추출하여 변수에 쉽게 할당할 수 있는 편리한 문법</li>
</ul>
<h4 id="1-배열의-구조-분해-할당">1. 배열의 구조 분해 할당</h4>
<pre><code class="language-javascript">let arr = [1, 2, 3];

let [one, two, three, four = 4] = arr;
// four = 4 는 값이 할당되지 않을 경우 초기값을 4로 할당하겠다는 뜻

console.log(one);   // 출력: 1
console.log(two);   // 출력: 2
console.log(three); // 출력: 3
console.log(four);  // 출력: 4 (기본값)</code></pre>
<h4 id="2-객체의-구조-분해-할당">2. 객체의 구조 분해 할당</h4>
<pre><code class="language-javascript">let person = {
  name: &quot;이정환&quot;,
  age: 27,
  hobby: &quot;테니스&quot;,
};

let { age: myAge, hobby, name, extra = &quot;hello&quot; } = person;

console.log(myAge); // 출력: 27
console.log(hobby); // 출력: 테니스
console.log(name);  // 출력: 이정환
console.log(extra); // 출력: hello (기본값)</code></pre>
<li>객체 person에서 age, hobby, name 속성을 각각 myAge, hobby, name 변수에 할당한다.</li>
<li>extra 속성은 person에 없으므로 기본값 "hello"가 할당된다.</li>
<li>age: myAge처럼 속성명을 변경할 수도 있다.</li>

<h4 id="3-함수-매개변수에서-객체-구조-분해-할당-사용">3. 함수 매개변수에서 객체 구조 분해 할당 사용</h4>
<pre><code class="language-javascript">const func = ({ name, age, hobby, extra }) =&gt; {
  console.log(name, age, hobby, extra);
};

let person = {
  name: &quot;이정환&quot;,
  age: 27,
  hobby: &quot;테니스&quot;,
};

func(person);
// 출력: 이정환 27 테니스 undefined</code></pre>
<p>함수 매개변수에 구조 분해 할당을 해놓은 채 함수에 객체를 매개변수로  넣어주면 구조 분해를 통해 함수 내부 실행문에서 사용하여 log를 찍는 것을 확인할 수 있음 이때, extra는 존재하지 않기 때문에 falsy한 값인 undefined 가 출력됨.</p>
<p>이를 활용하여 </p>
<h4 id="배열-요소-스왑">배열 요소 스왑</h4>
<pre><code class="language-javascript">let a = 1, b = 2;
[a, b] = [b, a];

console.log(a); // 출력: 2
console.log(b); // 출력: 1</code></pre>
<h4 id="기본값-설정">기본값 설정</h4>
<pre><code class="language-javascript">let options = { timeout: 100 };
let { timeout, retries = 3 } = options;

console.log(timeout); // 출력: 100
console.log(retries); // 출력: 3 (기본값)</code></pre>
<h4 id="함수의-리턴값-처리">함수의 리턴값 처리</h4>
<pre><code class="language-javascript">function getUser() {
  return [&quot;이정환&quot;, 27];
}

let [name, age] = getUser();
console.log(name); // 출력: 이정환
console.log(age);  // 출력: 27</code></pre>
<p>다양한 상황에서 유용하게 활용될 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] Falsy한 값 7가지 ]]></title>
            <link>https://velog.io/@_error/JavaScript-Falsy%ED%95%9C-%EA%B0%92-7%EA%B0%80%EC%A7%80</link>
            <guid>https://velog.io/@_error/JavaScript-Falsy%ED%95%9C-%EA%B0%92-7%EA%B0%80%EC%A7%80</guid>
            <pubDate>Thu, 16 Jan 2025 01:54:25 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h1 id="falsy한-값이란">Falsy한 값이란?</h1>
</blockquote>
<p><strong>Falsy</strong> 값이란 Boolean 문맥에서 <strong>false</strong>로 평가되는 값들을 말한다. JavaScript에는** 총 7가지의 Falsy 값**이 있으며, 이 값들은 명시적으로 false로 변환되지 않더라도 논리 평가 시 거짓으로 간주된다.</p>
<h3 id="1--span-stylebackground-color-f5f0ffundefinedspan">1.  <span style='background-color: #f5f0ff'>undefined</span></h3>
<p><code>undefined</code>는 JavaScript에서 선언된 변수에 값이 할당되지 않은 상태를 나타낸다.</p>
<h3 id="2--span-stylebackground-color-f5f0ffnullspan">2.  <span style='background-color: #f5f0ff'>null</span></h3>
<p><code>null</code>은 의도적으로 비어 있는 값(값이 없음을 나타내는 값)으로 설정된 상태.</p>
<h3 id="3--span-stylebackground-color-f5f0ff0span">3.  <span style='background-color: #f5f0ff'>0</span></h3>
<p>숫자 <code>0</code>은 Falsy로 평가.</p>
<h3 id="4--span-stylebackground-color-f5f0ff-0span">4.  <span style='background-color: #f5f0ff'>-0</span></h3>
<p><code>-0</code> 또한 <code>0</code>과 동일하게 Falsy로 평가됩니다. <code>0</code>과 <code>-0</code>은 JavaScript에서 같은 값으로 간주.</p>
<h3 id="5--span-stylebackground-color-f5f0ffnanspan">5.  <span style='background-color: #f5f0ff'>NaN</span></h3>
<p><code>NaN</code>(Not-a-Number)은 숫자가 아닌 값 또는 계산이 실패했을 때 생성되며, Falsy로 평가됨.</p>
<h3 id="6--span-stylebackground-color-f5f0ff빈-문자열-span">6.  <span style='background-color: #f5f0ff'>빈 문자열 &quot;&quot;</span></h3>
<p>길이가 0인 <code>빈 문자열</code>은 Falsy입니다. 여기에는 큰따옴표<code>(&quot;&quot;)</code>와 작은따옴표<code>(&#39;&#39;)</code> 모두 포함.</p>
<h3 id="7--span-stylebackground-color-f5f0ff-bigint-0nspan">7.  <span style='background-color: #f5f0ff'> (BigInt) 0n</span></h3>
<p>BigInt 타입의 <code>0n</code>은 숫자 <code>0</code>처럼 Falsy로 평가됨.</p>
<br>

<br>

<blockquote>
<h1 id="falsy가-아닌-truthy-값은">Falsy가 아닌 Truthy 값은?</h1>
</blockquote>
<p>Falsy 한 7개의 값을 제외한 모든 값은 Truthy한 값이며 이를 활용하여</p>
<pre><code class="language-javascript">let username = &quot;&quot;;
let defaultName = username || &quot;Guest&quot;;
console.log(defaultName); // 출력: Guest
</code></pre>
<p>username이 Falsy 값(&quot;&quot;)이므로 defaultName에 &quot;Guest&quot;가 할당되도록 응용할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 오늘 날짜 구하기]]></title>
            <link>https://velog.io/@_error/JavaScript-%EC%98%A4%EB%8A%98-%EB%82%A0%EC%A7%9C-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@_error/JavaScript-%EC%98%A4%EB%8A%98-%EB%82%A0%EC%A7%9C-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 27 Dec 2024 06:02:38 GMT</pubDate>
            <description><![CDATA[<h2 id="yyyy-mm-ddt060005044629">YYYY-MM-DDT06:00:05.044629</h2>
<p>ISO 포맷팅을 사용하면 ISO 8601 형식으로 가져온 뒤 필요한 오늘 날자를 가져오기위에
split() 메서드를 사용하여 짤라 사용한다.</p>
<h2 id="오늘-날짜-구하기">오늘 날짜 구하기</h2>
<pre><code class="language-javascript">
//오늘 날짜 구하기
const date = new Date();
const today = date.toISOString().split(&quot;T&quot;)[0];

console.log(today);  // 예: 2024-12-27</code></pre>
<h2 id="오늘-시간-구하기">오늘 시간 구하기</h2>
<pre><code class="language-javascript">// 오늘 시간 구하기
const time = date.toISOString().split(&quot;T&quot;)[1];

console.log(time);  // 예: 06:00:05.044629</code></pre>
<h2 id="오늘-시간-소수점버리기">오늘 시간 소수점버리기</h2>
<pre><code class="language-javascript">// 오늘 시간 구하기 (소수점 이하 제거)
const time = date.toISOString().split(&quot;T&quot;)[1].split(&quot;.&quot;)[0];

console.log(time);  // 예: 06:00:05
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript]consolo.log 자동완성 셋팅하기]]></title>
            <link>https://velog.io/@_error/JavaScriptconsolo.log-%EC%9E%90%EB%8F%99%EC%99%84%EC%84%B1-%EC%85%8B%ED%8C%85%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@_error/JavaScriptconsolo.log-%EC%9E%90%EB%8F%99%EC%99%84%EC%84%B1-%EC%85%8B%ED%8C%85%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 31 Oct 2024 00:05:44 GMT</pubDate>
            <description><![CDATA[<p><code>Consolo.log</code> <span style='color: red'><strong>자동완성 시키기</strong></span>
<img src="https://velog.velcdn.com/images/_error/post/c6cd1542-aced-4a17-a159-6433a02e28f1/image.png" alt="">
<strong><code>File</code></strong> - <strong><code>Preferencess</code></strong> - <strong><code>Configure Snippets</code></strong></p>
<p><img src="https://velog.velcdn.com/images/_error/post/1f7b90f0-59c2-4287-afb0-59c3d8e2c709/image.png" alt=""></p>
<p>검색 창이 하나 뜨는데 
<strong>&quot;<span style='color: red'>javascript.json</span>&quot;</strong> 검색 
<img src="https://velog.velcdn.com/images/_error/post/e96da1a2-61bb-41e3-be39-acf53b97205e/image.png" alt="">
들어가보면 아래와 같은 코드들이 주석처리되어있다. 사용법이 안내되어있고 <code>Example :</code> 아래부분부터 복사해서 입 맛에 맞게 셋팅한다.
<img src="https://velog.velcdn.com/images/_error/post/31b18807-1ab4-4b53-8817-02053e3ce869/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/_error/post/370cd68b-e33f-44a8-8630-4a4c2b4ab74c/image.png" alt=""></p>
<pre><code class="language-javascript">     &quot;Print to console&quot;: {
         &quot;prefix&quot;: &quot;cl&quot;,
         &quot;body&quot;: [
             &quot;console.log();&quot;
         ],
         &quot;description&quot;: &quot;Log output to console&quot;
     },
</code></pre>
<p><code>&quot;prefix&quot;: &quot;cl&quot;</code> 단축어 셋팅 (개인취향)
<code>&quot;body&quot;: [
             &quot;console.log();&quot;
         ]</code> 단축어가 실행됐을 때 생성될 내용</p>
<p> cl로 셋팅하여 
 <img src="https://velog.velcdn.com/images/_error/post/a0f8acb3-8491-4085-afff-8efdabb3f89a/image.png" alt="">
🥳 cl 이 정상적으로 셋팅 완료 🥳</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 기본 유효성 검사 기초]]></title>
            <link>https://velog.io/@_error/JavaScript-%EA%B8%B0%EB%B3%B8-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@_error/JavaScript-%EA%B8%B0%EB%B3%B8-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Mon, 28 Oct 2024 08:44:56 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/_error/post/f346e3bc-022b-47a5-b72b-8a74ba91d23f/image.png" alt=""></p>
<p>간단한 form으로 유효성검사 진행하기.</p>
<blockquote>
<p><strong>HTML</strong></p>
</blockquote>
<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;title&gt;Document&lt;/title&gt;
    &lt;!-- 외부스타일 연결방식 --&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;/자바스크립트설명/폼/폼문제.css&quot; /&gt;
    &lt;style&gt;
      .flex {
        display: flex;
      }
      .justify-between {
        justify-content: space-between;
      }
      .confirm-btn {
        cursor: pointer;
        height: 2.5rem;
      }
      .color-orangered {
        color: orangered;
      }
      .hidden {
        display: none;
      }
    &lt;/style&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div class=&quot;demo-page&quot;&gt;
      &lt;main class=&quot;demo-page-content&quot;&gt;
        &lt;section&gt;
          &lt;form name=&quot;signForm&quot;&gt;
            &lt;div class=&quot;href-target&quot; id=&quot;input-types&quot;&gt;&lt;/div&gt;
            &lt;h1&gt;회원가입&lt;/h1&gt;
            &lt;p&gt;회원가입을 위한 정보를 입력해주세요&lt;/p&gt;

            &lt;div class=&quot;nice-form-group&quot;&gt;
              &lt;!-- label태그의 for와 input태그의 id값이랑 동일하게 설정하여 연결(아이디글씨 클릭해도 input이 선택되도록) --&gt;
              &lt;!--  id=&quot;userId&quot; name=&quot;userId&quot;  id 값와 name 값은 웬만해서 동일하게 설정한다. --&gt;
              &lt;label for=&quot;userId&quot;&gt;아이디&lt;/label&gt;
              &lt;input type=&quot;text&quot; id=&quot;userId&quot; name=&quot;userId&quot; placeholder=&quot;Your Id&quot; /&gt;
            &lt;/div&gt;
            &lt;p id=&quot;w-userId&quot; class=&quot;color-orangered hidden&quot;&gt;아이디를 입력하세요.&lt;/p&gt;

            &lt;div class=&quot;nice-form-group&quot;&gt;
              &lt;label for=&quot;userPw&quot;&gt;비밀번호&lt;/label&gt;
              &lt;input type=&quot;password&quot; id=&quot;userPw&quot; name=&quot;userPw&quot; placeholder=&quot;Your Pw&quot; /&gt;
            &lt;/div&gt;
            &lt;p id=&quot;w-userPw&quot; class=&quot;color-orangered hidden&quot;&gt;비밀번호를 입력하세요/&lt;/p&gt;
            &lt;div class=&quot;nice-form-group&quot;&gt;
              &lt;label for=&quot;userConfirm&quot;&gt;비밀번호 확인&lt;/label&gt;
              &lt;input type=&quot;password&quot; id=&quot;userConfirm&quot; name=&quot;userConfirm&quot; placeholder=&quot;Your Pw Confirm&quot; style=&quot;width: 80%&quot; /&gt;
              &lt;div class=&quot;to-reset confirm-btn&quot; onclick=&quot;goUserPwConfirm()&quot;&gt;확인&lt;/div&gt;
            &lt;/div&gt;
            &lt;p id=&quot;w-userPwConfirm&quot; class=&quot;color-orangered hidden&quot;&gt;확인할 비밀번호를 입력하세요.&lt;/p&gt;

            &lt;div class=&quot;nice-form-group&quot;&gt;
              &lt;label for=&quot;userPhone&quot;&gt;전화번호&lt;/label&gt;
              &lt;input type=&quot;tel&quot; id=&quot;userPhone&quot; name=&quot;userPhone&quot; placeholder=&quot;Your phone&quot; /&gt;
            &lt;/div&gt;

            &lt;div class=&quot;nice-form-group&quot;&gt;
              &lt;label for=&quot;userName&quot;&gt;이름&lt;/label&gt;
              &lt;input type=&quot;text&quot; id=&quot;userName&quot; name=&quot;userName&quot; placeholder=&quot;Your name&quot; /&gt;
            &lt;/div&gt;
            &lt;p id=&quot;w-userName&quot; class=&quot;color-orangered hidden&quot;&gt;이름을 입력하세요.&lt;/p&gt;

            &lt;div class=&quot;nice-form-group&quot;&gt;
              &lt;label for=&quot;userBirth&quot;&gt;생년월일8자리&lt;/label&gt;
              &lt;input type=&quot;text&quot; id=&quot;userBirth&quot; name=&quot;userBirth&quot; placeholder=&quot;Your birth&quot; /&gt;
            &lt;/div&gt;
            &lt;p id=&quot;w-userBirth&quot; class=&quot;color-orangered hidden&quot;&gt;&lt;/p&gt;

            &lt;div class=&quot;nice-form-group&quot;&gt;
              &lt;label for=&quot;userRegion&quot;&gt;사는 지역&lt;/label&gt;
              &lt;select id=&quot;userRegion&quot; name=&quot;userRegion&quot;&gt;
                &lt;option value=&quot;&quot;&gt;- 지역을 선택하세요 -&lt;/option&gt;
                &lt;option value=&quot;R001&quot;&gt;서울&lt;/option&gt;
                &lt;option value=&quot;R002&quot;&gt;경기&lt;/option&gt;
                &lt;option value=&quot;R003&quot;&gt;대전&lt;/option&gt;
                &lt;option value=&quot;R004&quot;&gt;부산&lt;/option&gt;
              &lt;/select&gt;
            &lt;/div&gt;
            &lt;p id=&quot;w-userRegion&quot; class=&quot;color-orangered hidden&quot;&gt;지역을 선택하세요.&lt;/p&gt;

            &lt;div class=&quot;nice-form-group&quot;&gt;
              &lt;label for=&quot;userPhoto&quot;&gt;프로필 사진 등록하기&lt;/label&gt;
              &lt;input id=&quot;userPhoto&quot; name=&quot;userPhoto&quot; type=&quot;file&quot; /&gt;
            &lt;/div&gt;

            &lt;fieldset class=&quot;nice-form-group&quot;&gt;
              &lt;legend&gt;성별&lt;/legend&gt;
              &lt;!-- radio타입에서 name 을 동일하게 설정하여 둘 중 하나만 선택될 수 있게 설정 --&gt;
              &lt;div class=&quot;nice-form-group&quot;&gt;
                &lt;input type=&quot;radio&quot; id=&quot;male&quot; name=&quot;userGender&quot; checked=&quot;checked&quot; value=&quot;G001&quot; /&gt;
                &lt;label for=&quot;male&quot;&gt;남자&lt;/label&gt;
              &lt;/div&gt;

              &lt;div class=&quot;nice-form-group&quot;&gt;
                &lt;input type=&quot;radio&quot; id=&quot;female&quot; name=&quot;userGender&quot; value=&quot;G002&quot; /&gt;
                &lt;label for=&quot;female&quot;&gt;여자&lt;/label&gt;
              &lt;/div&gt;
            &lt;/fieldset&gt;

            &lt;fieldset class=&quot;nice-form-group&quot;&gt;
              &lt;legend&gt;관심분야&lt;/legend&gt;
              &lt;div class=&quot;nice-form-group&quot;&gt;
                &lt;input type=&quot;checkbox&quot; id=&quot;css&quot; name=&quot;userField&quot; value=&quot;F001&quot; /&gt;
                &lt;label for=&quot;css&quot;&gt;CSS&lt;/label&gt;
              &lt;/div&gt;

              &lt;div class=&quot;nice-form-group&quot;&gt;
                &lt;input type=&quot;checkbox&quot; id=&quot;html&quot; name=&quot;userField&quot; value=&quot;F002&quot; /&gt;
                &lt;label for=&quot;html&quot;&gt;HTML&lt;/label&gt;
              &lt;/div&gt;

              &lt;div class=&quot;nice-form-group&quot;&gt;
                &lt;input type=&quot;checkbox&quot; id=&quot;js&quot; name=&quot;userField&quot; value=&quot;F003&quot; /&gt;
                &lt;label for=&quot;js&quot;&gt;Javascript&lt;/label&gt;
              &lt;/div&gt;

              &lt;div class=&quot;nice-form-group&quot;&gt;
                &lt;input type=&quot;checkbox&quot; id=&quot;java&quot; name=&quot;userField&quot; value=&quot;F004&quot; /&gt;
                &lt;label for=&quot;java&quot;&gt;Java&lt;/label&gt;
              &lt;/div&gt;
            &lt;/fieldset&gt;

            &lt;details&gt;
              &lt;summary&gt;
                &lt;div class=&quot;toggle-code&quot; onclick=&quot;goSignUp()&quot;&gt;회원가입요청&lt;/div&gt;
              &lt;/summary&gt;
            &lt;/details&gt;
          &lt;/form&gt;
        &lt;/section&gt;
      &lt;/main&gt;
    &lt;/div&gt;

    &lt;script&gt;
      /* 입력요소 */
      const userIdEl = document.getElementById(&quot;userId&quot;);
      const userPwEl = document.getElementById(&quot;userPw&quot;);
      const userPwConfirmEl = document.getElementById(&quot;userConfirm&quot;);
      const userPhoneEl = document.getElementById(&quot;userPhone&quot;);
      const userNameEl = document.getElementById(&quot;userName&quot;);

      const userBirthEl = document.getElementById(&quot;userBirth&quot;);
      //지역값 출력 수정필요(지역코드로 나옴)
      const userRegionEl = document.getElementById(&quot;userRegion&quot;);
      console.log(userRegionEl);
      const userPhotoEl = document.getElementById(&quot;userPhoto&quot;);

      /*경고문구요소*/
      const wUserPwEl = document.getElementById(&quot;w-userPw&quot;);
      const wUserPwConfirmEl = document.getElementById(&quot;w-userPwConfirm&quot;);
      const wUserIdEl = document.getElementById(&quot;w-userId&quot;);
      const wUserNameEl = document.getElementById(&quot;w-userName&quot;);
      const wUserRegionEl = document.getElementById(&quot;w-userRegion&quot;);
      const wUserBirthEl = document.getElementById(&quot;w-userBirth&quot;);

      /* 비밀번호 확인 function */
      let isConfirm = false;
      const goUserPwConfirm = () =&gt; {
        console.log(userPwEl.value);
        console.log(userPwConfirmEl.value);

        if (!userPwEl.value) {
          wUserPwEl.classList.remove(&quot;hidden&quot;);
          return;
        } else {
          wUserPwEl.classList.add(&quot;hidden&quot;);
        }

        if (!userPwConfirmEl.value) {
          wUserPwConfirmEl.classList.remove(&quot;hidden&quot;);
          return;
        } else {
          wUserPwConfirmEl.classList.add(&quot;hidden&quot;);
        }

        //2. 비밀번호 = 비밀번호 확인 일치여부
        if (userPwEl.value == userPwConfirmEl.value) {
          alert(&quot;확인 완료되었습니다.&quot;);
          isConfirm = true;
        } else {
          alert(&quot;비밀번호가 일치하지 않습니다.&quot;);
          isConfirm = false;
        }
      };

      /* 유효성검사 function */

      const validationCheck = () =&gt; {
        // Id유효성검사
        if (!userIdEl.value) {
          wUserIdEl.classList.remove(&quot;hidden&quot;);
          return false;
        } else {
          wUserIdEl.classList.add(&quot;hidden&quot;);
        }
        // Name유효성검사
        if (!userNameEl.value) {
          wUserNameEl.classList.remove(&quot;hidden&quot;);
          return false;
        } else {
          wUserNameEl.classList.add(&quot;hidden&quot;);
        }

        // 생년월일 유효성검사

        if (userBirthEl.value.length != 8) {
          wUserBirthEl.innerText = &quot;생년월일은 8자리입니다.&quot;;
          wUserBirthEl.classList.remove(&quot;hidden&quot;);
          userBirthEl.value = userBirthEl.value.replace(/[^A-Z0-9+_.]/g, &quot;&quot;);
          return false;
        } else {
          wUserBirthEl.classList.add(&quot;hidden&quot;);
        }
        if (isNaN(Number(userBirthEl.value))) {
          wUserBirthEl.innerText = &quot;생년월일은 숫자만 입력하세요.&quot;;
          wUserBirthEl.classList.remove(&quot;hidden&quot;);
          userBirthEl.value = userBirthEl.value.replace(/[^A-Z0-9+_.]/g, &quot;&quot;);
          return false;
        } else {
          wUserBirthEl.classList.add(&quot;hidden&quot;);
        }

        // Region유효성검사
        if (!userRegionEl.value) {
          wUserRegionEl.classList.remove(&quot;hidden&quot;);
          return false;
        } else {
          wUserRegionEl.classList.add(&quot;hidden&quot;);
        }

        if (!isConfirm) {
          alert(`비밀번호 확인을 먼저 진행해주세요.`);
          return false;
        }
        return true;
      };

      const goSignUp = () =&gt; {
        //유효성검사
        const res = validationCheck();

        console.log(res);

        if (res) {
          //성별, 분야 오류
          const userGenderEl = document.querySelector(&quot;[name=&#39;userGender&#39;]:checked&quot;);

          const userFieldEl = document.querySelectorAll(&quot;[name=&#39;userField&#39;]:checked&quot;);
          const list = Array.from(userFieldEl, (item) =&gt; item.value);

          //입력요소
          console.log(userPhotoEl.files);
          //옵셔널체이닝 ?. = ?앞의 내용들이 undifined라면 undefined로 변환해준다.
          // 없다면 오류가 발생하지만 옵셔널체이닝으로 undefined 라는 데이터 타입으로 리턴한다.
          const photoName = userPhotoEl.files[0]?.name || &quot;파일없음&quot;;

          const resultObj = {
            id: userIdEl.value,
            pw: userPwEl.value,
            phone: userPhoneEl.value,
            name: userNameEl.value,
            birth: userBirthEl.value,
            region: userRegionEl.value,
            profile: photoName,
            gender: userGenderEl.value,
            field: list.join(),
          };

          console.log(resultObj);
        }
      };
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre><blockquote>
<p><strong>CSS</strong></p>
</blockquote>
<pre><code class="language-css">@import url(&quot;https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&amp;display=swap&quot;);
a,
abbr,
acronym,
address,
applet,
article,
aside,
audio,
b,
big,
blockquote,
body,
canvas,
caption,
center,
cite,
code,
dd,
del,
details,
dfn,
div,
dl,
dt,
em,
embed,
fieldset,
figcaption,
figure,
footer,
form,
h1,
h2,
h3,
h4,
h5,
h6,
header,
hgroup,
html,
i,
iframe,
img,
ins,
kbd,
label,
legend,
li,
mark,
menu,
nav,
object,
ol,
output,
p,
pre,
q,
ruby,
s,
samp,
section,
small,
span,
strike,
strong,
sub,
summary,
sup,
table,
tbody,
td,
tfoot,
th,
thead,
time,
tr,
tt,
u,
ul,
var,
video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: initial;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
  display: block;
}
body {
  line-height: 1;
}
ol,
ul {
  list-style: none;
}
blockquote,
q {
  quotes: none;
}
blockquote:after,
blockquote:before,
q:after,
q:before {
  content: &quot;&quot;;
  content: none;
}
table {
  border-collapse: collapse;
  border-spacing: 0;
}
.nice-form-group {
  --nf-input-size: 1rem;
  --nf-input-font-size: calc(var(--nf-input-size) * 0.875);
  --nf-small-font-size: calc(var(--nf-input-size) * 0.875);
  --nf-input-font-family: inherit;
  --nf-label-font-family: inherit;
  --nf-input-color: #20242f;
  --nf-input-border-radius: 0.25rem;
  --nf-input-placeholder-color: #929292;
  --nf-input-border-color: #c0c4c9;
  --nf-input-border-width: 1px;
  --nf-input-border-style: solid;
  --nf-input-border-bottom-width: 2px;
  --nf-input-focus-border-color: #3b4ce2;
  --nf-input-background-color: #f9fafb;
  --nf-invalid-input-border-color: var(--nf-input-border-color);
  --nf-invalid-input-background-color: var(--nf-input-background-color);
  --nf-invalid-input-color: var(--nf-input-color);
  --nf-valid-input-border-color: var(--nf-input-border-color);
  --nf-valid-input-background-color: var(--nf-input-background-color);
  --nf-valid-input-color: inherit;
  --nf-invalid-input-border-bottom-color: red;
  --nf-valid-input-border-bottom-color: green;
  --nf-label-font-size: var(--nf-small-font-size);
  --nf-label-color: #374151;
  --nf-label-font-weight: 500;
  --nf-slider-track-background: #dfdfdf;
  --nf-slider-track-height: 0.25rem;
  --nf-slider-thumb-size: calc(var(--nf-slider-track-height) * 4);
  --nf-slider-track-border-radius: var(--nf-slider-track-height);
  --nf-slider-thumb-border-width: 2px;
  --nf-slider-thumb-border-focus-width: 1px;
  --nf-slider-thumb-border-color: #fff;
  --nf-slider-thumb-background: var(--nf-input-focus-border-color);
  display: block;
  margin-top: calc(var(--nf-input-size) * 1.5);
  line-height: 1;
  white-space: nowrap;
  --switch-orb-size: var(--nf-input-size);
  --switch-orb-offset: calc(var(--nf-input-border-width) * 2);
  --switch-width: calc(var(--nf-input-size) * 2.5);
  --switch-height: calc(var(--nf-input-size) * 1.25 + var(--switch-orb-offset));
}
.nice-form-group &gt; label {
  font-weight: var(--nf-label-font-weight);
  display: block;
  color: var(--nf-label-color);
  font-size: var(--nf-label-font-size);
  font-family: var(--nf-label-font-family);
  margin-bottom: calc(var(--nf-input-size) / 2);
  white-space: normal;
}
.nice-form-group &gt; label + small {
  font-style: normal;
}
.nice-form-group small {
  font-family: var(--nf-input-font-family);
  display: block;
  font-weight: 400;
  opacity: 0.75;
  font-size: var(--nf-small-font-size);
  margin-bottom: calc(var(--nf-input-size) * 0.75);
}
.nice-form-group small:last-child {
  margin-bottom: 0;
}
.nice-form-group &gt; legend {
  font-weight: var(--nf-label-font-weight);
  display: block;
  color: var(--nf-label-color);
  font-size: var(--nf-label-font-size);
  font-family: var(--nf-label-font-family);
  margin-bottom: calc(var(--nf-input-size) / 5);
}
.nice-form-group &gt; .nice-form-group {
  margin-top: calc(var(--nf-input-size) / 2);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;],
.nice-form-group &gt; input[type=&quot;date&quot;],
.nice-form-group &gt; input[type=&quot;email&quot;],
.nice-form-group &gt; input[type=&quot;month&quot;],
.nice-form-group &gt; input[type=&quot;number&quot;],
.nice-form-group &gt; input[type=&quot;password&quot;],
.nice-form-group &gt; input[type=&quot;radio&quot;],
.nice-form-group &gt; input[type=&quot;search&quot;],
.nice-form-group &gt; input[type=&quot;tel&quot;],
.nice-form-group &gt; input[type=&quot;text&quot;],
.nice-form-group &gt; input[type=&quot;time&quot;],
.nice-form-group &gt; input[type=&quot;url&quot;],
.nice-form-group &gt; input[type=&quot;week&quot;],
.nice-form-group &gt; select,
.nice-form-group &gt; textarea {
  background: var(--nf-input-background-color);
  font-family: inherit;
  font-size: var(--nf-input-font-size);
  border-bottom-width: var(--nf-input-border-width);
  font-family: var(--nf-input-font-family);
  box-shadow: none;
  border-radius: var(--nf-input-border-radius);
  border: var(--nf-input-border-width) var(--nf-input-border-style) var(--nf-input-border-color);
  border-bottom: var(--nf-input-border-bottom-width) var(--nf-input-border-style) var(--nf-input-border-color);
  color: var(--nf-input-color);
  width: 100%;
  padding: calc(var(--nf-input-size) * 0.75);
  height: calc(var(--nf-input-size) * 2.75);
  line-height: normal;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  transition: all 0.15s ease-out;
  --icon-padding: calc(var(--nf-input-size) * 2.25);
  --icon-background-offset: calc(var(--nf-input-size) * 0.75);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;date&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;email&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;month&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;number&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;password&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;radio&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;search&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;tel&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;text&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;time&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;url&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; input[type=&quot;week&quot;]:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; select:required:not(:placeholder-shown):invalid,
.nice-form-group &gt; textarea:required:not(:placeholder-shown):invalid {
  background-color: var(--nf-invalid-input-background-color);
  border-bottom-color: var(--nf-valid-input-border-color);
  border-color: var(--nf-valid-input-border-color) var(--nf-valid-input-border-color) var(--nf-invalid-input-border-bottom-color);
  color: var(--nf-invalid-input-color);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;date&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;email&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;month&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;number&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;password&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;radio&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;search&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;tel&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;text&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;time&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;url&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; input[type=&quot;week&quot;]:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; select:required:not(:placeholder-shown):invalid:focus,
.nice-form-group &gt; textarea:required:not(:placeholder-shown):invalid:focus {
  background-color: var(--nf-input-background-color);
  border-color: var(--nf-input-border-color);
  color: var(--nf-input-color);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;date&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;email&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;month&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;number&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;password&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;radio&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;search&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;tel&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;text&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;time&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;url&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; input[type=&quot;week&quot;]:required:not(:placeholder-shown):valid,
.nice-form-group &gt; select:required:not(:placeholder-shown):valid,
.nice-form-group &gt; textarea:required:not(:placeholder-shown):valid {
  background-color: var(--nf-valid-input-background-color);
  border-bottom-color: var(--nf-valid-input-border-color);
  border-color: var(--nf-valid-input-border-color) var(--nf-valid-input-border-color) var(--nf-valid-input-border-bottom-color);
  color: var(--nf-valid-input-color);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;date&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;email&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;month&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;number&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;password&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;radio&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;search&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;tel&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;text&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;time&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;url&quot;]:disabled,
.nice-form-group &gt; input[type=&quot;week&quot;]:disabled,
.nice-form-group &gt; select:disabled,
.nice-form-group &gt; textarea:disabled {
  cursor: not-allowed;
  opacity: 0.75;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;date&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;email&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;month&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;number&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;password&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;radio&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;search&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;tel&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;text&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;time&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;url&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; input[type=&quot;week&quot;]::-webkit-input-placeholder,
.nice-form-group &gt; select::-webkit-input-placeholder,
.nice-form-group &gt; textarea::-webkit-input-placeholder {
  color: var(--nf-input-placeholder-color);
  letter-spacing: 0;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;date&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;email&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;month&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;number&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;password&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;radio&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;search&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;tel&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;text&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;time&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;url&quot;]:-ms-input-placeholder,
.nice-form-group &gt; input[type=&quot;week&quot;]:-ms-input-placeholder,
.nice-form-group &gt; select:-ms-input-placeholder,
.nice-form-group &gt; textarea:-ms-input-placeholder {
  color: var(--nf-input-placeholder-color);
  letter-spacing: 0;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;checkbox&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;date&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;date&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;email&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;email&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;month&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;month&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;number&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;number&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;password&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;password&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;radio&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;radio&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;search&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;search&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;tel&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;tel&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;text&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;text&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;time&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;time&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;url&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;url&quot;]::-moz-placeholder,
.nice-form-group &gt; input[type=&quot;week&quot;]:-moz-placeholder,
.nice-form-group &gt; input[type=&quot;week&quot;]::-moz-placeholder,
.nice-form-group &gt; select:-moz-placeholder,
.nice-form-group &gt; select::-moz-placeholder,
.nice-form-group &gt; textarea:-moz-placeholder,
.nice-form-group &gt; textarea::-moz-placeholder {
  color: var(--nf-input-placeholder-color);
  letter-spacing: 0;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]:focus,
.nice-form-group &gt; input[type=&quot;date&quot;]:focus,
.nice-form-group &gt; input[type=&quot;email&quot;]:focus,
.nice-form-group &gt; input[type=&quot;month&quot;]:focus,
.nice-form-group &gt; input[type=&quot;number&quot;]:focus,
.nice-form-group &gt; input[type=&quot;password&quot;]:focus,
.nice-form-group &gt; input[type=&quot;radio&quot;]:focus,
.nice-form-group &gt; input[type=&quot;search&quot;]:focus,
.nice-form-group &gt; input[type=&quot;tel&quot;]:focus,
.nice-form-group &gt; input[type=&quot;text&quot;]:focus,
.nice-form-group &gt; input[type=&quot;time&quot;]:focus,
.nice-form-group &gt; input[type=&quot;url&quot;]:focus,
.nice-form-group &gt; input[type=&quot;week&quot;]:focus,
.nice-form-group &gt; select:focus,
.nice-form-group &gt; textarea:focus {
  outline: none;
  border-color: var(--nf-input-focus-border-color);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;] + small,
.nice-form-group &gt; input[type=&quot;date&quot;] + small,
.nice-form-group &gt; input[type=&quot;email&quot;] + small,
.nice-form-group &gt; input[type=&quot;month&quot;] + small,
.nice-form-group &gt; input[type=&quot;number&quot;] + small,
.nice-form-group &gt; input[type=&quot;password&quot;] + small,
.nice-form-group &gt; input[type=&quot;radio&quot;] + small,
.nice-form-group &gt; input[type=&quot;search&quot;] + small,
.nice-form-group &gt; input[type=&quot;tel&quot;] + small,
.nice-form-group &gt; input[type=&quot;text&quot;] + small,
.nice-form-group &gt; input[type=&quot;time&quot;] + small,
.nice-form-group &gt; input[type=&quot;url&quot;] + small,
.nice-form-group &gt; input[type=&quot;week&quot;] + small,
.nice-form-group &gt; select + small,
.nice-form-group &gt; textarea + small {
  margin-top: 0.5rem;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;date&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;email&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;month&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;number&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;password&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;radio&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;search&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;tel&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;text&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;time&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;url&quot;].icon-left,
.nice-form-group &gt; input[type=&quot;week&quot;].icon-left,
.nice-form-group &gt; select.icon-left,
.nice-form-group &gt; textarea.icon-left {
  background-position: left var(--icon-background-offset) bottom 50%;
  padding-left: var(--icon-padding);
  background-size: var(--nf-input-size);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;date&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;email&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;month&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;number&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;password&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;radio&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;search&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;tel&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;text&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;time&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;url&quot;].icon-right,
.nice-form-group &gt; input[type=&quot;week&quot;].icon-right,
.nice-form-group &gt; select.icon-right,
.nice-form-group &gt; textarea.icon-right {
  background-position: right var(--icon-background-offset) bottom 50%;
  padding-right: var(--icon-padding);
  background-size: var(--nf-input-size);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;date&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;email&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;month&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;number&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;password&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;radio&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;search&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;tel&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;text&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;time&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;url&quot;]:-webkit-autofill,
.nice-form-group &gt; input[type=&quot;week&quot;]:-webkit-autofill,
.nice-form-group &gt; select:-webkit-autofill,
.nice-form-group &gt; textarea:-webkit-autofill {
  padding: calc(var(--nf-input-size) * 0.75) !important;
}
.nice-form-group &gt; input[type=&quot;search&quot;]:placeholder-shown {
  background-image: url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;16&#39; height=&#39;16&#39; viewBox=&#39;0 0 24 24&#39; fill=&#39;none&#39; stroke=&#39;%236B7280&#39; stroke-width=&#39;2&#39; stroke-linecap=&#39;round&#39; stroke-linejoin=&#39;round&#39; class=&#39;feather feather-search&#39;%3E%3Ccircle cx=&#39;11&#39; cy=&#39;11&#39; r=&#39;8&#39;/%3E%3Cpath d=&#39;M21 21l-4.35-4.35&#39;/%3E%3C/svg%3E&quot;);
  background-position: left calc(var(--nf-input-size) * 0.75) bottom 50%;
  padding-left: calc(var(--nf-input-size) * 2.25);
  background-size: var(--nf-input-size);
  background-repeat: no-repeat;
}
.nice-form-group &gt; input[type=&quot;search&quot;]::-webkit-search-cancel-button {
  -webkit-appearance: none;
  width: var(--nf-input-size);
  height: var(--nf-input-size);
  background: url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;16&#39; height=&#39;16&#39; viewBox=&#39;0 0 24 24&#39; fill=&#39;none&#39; stroke=&#39;%236B7280&#39; stroke-width=&#39;2&#39; stroke-linecap=&#39;round&#39; stroke-linejoin=&#39;round&#39; class=&#39;feather feather-x&#39;%3E%3Cpath d=&#39;M18 6L6 18M6 6l12 12&#39;/%3E%3C/svg%3E&quot;);
}
.nice-form-group &gt; input[type=&quot;search&quot;]:focus {
  padding-left: calc(var(--nf-input-size) * 0.75);
  background-position: left calc(var(--nf-input-size) * -1) bottom 50%;
}
.nice-form-group &gt; input[type=&quot;email&quot;][class^=&quot;icon&quot;] {
  background-image: url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;16&#39; height=&#39;16&#39; viewBox=&#39;0 0 24 24&#39; fill=&#39;none&#39; stroke=&#39;%236B7280&#39; stroke-width=&#39;2&#39; stroke-linecap=&#39;round&#39; stroke-linejoin=&#39;round&#39; class=&#39;feather feather-at-sign&#39;%3E%3Ccircle cx=&#39;12&#39; cy=&#39;12&#39; r=&#39;4&#39;/%3E%3Cpath d=&#39;M16 8v5a3 3 0 006 0v-1a10 10 0 10-3.92 7.94&#39;/%3E%3C/svg%3E&quot;);
  background-repeat: no-repeat;
}
.nice-form-group &gt; input[type=&quot;tel&quot;][class^=&quot;icon&quot;] {
  background-image: url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;16&#39; height=&#39;16&#39; viewBox=&#39;0 0 24 24&#39; fill=&#39;none&#39; stroke=&#39;%236B7280&#39; stroke-width=&#39;2&#39; stroke-linecap=&#39;round&#39; stroke-linejoin=&#39;round&#39; class=&#39;feather feather-phone&#39;%3E%3Cpath d=&#39;M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72 12.84 12.84 0 00.7 2.81 2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45 12.84 12.84 0 002.81.7A2 2 0 0122 16.92z&#39;/%3E%3C/svg%3E&quot;);
  background-repeat: no-repeat;
}
.nice-form-group &gt; input[type=&quot;url&quot;][class^=&quot;icon&quot;] {
  background-image: url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;16&#39; height=&#39;16&#39; viewBox=&#39;0 0 24 24&#39; fill=&#39;none&#39; stroke=&#39;%236B7280&#39; stroke-width=&#39;2&#39; stroke-linecap=&#39;round&#39; stroke-linejoin=&#39;round&#39; class=&#39;feather feather-link&#39;%3E%3Cpath d=&#39;M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71&#39;/%3E%3Cpath d=&#39;M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71&#39;/%3E%3C/svg%3E&quot;);
  background-repeat: no-repeat;
}
.nice-form-group &gt; input[type=&quot;password&quot;] {
  letter-spacing: 2px;
}
.nice-form-group &gt; input[type=&quot;password&quot;][class^=&quot;icon&quot;] {
  background-image: url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;16&#39; height=&#39;16&#39; viewBox=&#39;0 0 24 24&#39; fill=&#39;none&#39; stroke=&#39;%236B7280&#39; stroke-width=&#39;2&#39; stroke-linecap=&#39;round&#39; stroke-linejoin=&#39;round&#39; class=&#39;feather feather-lock&#39;%3E%3Crect x=&#39;3&#39; y=&#39;11&#39; width=&#39;18&#39; height=&#39;11&#39; rx=&#39;2&#39; ry=&#39;2&#39;/%3E%3Cpath d=&#39;M7 11V7a5 5 0 0110 0v4&#39;/%3E%3C/svg%3E&quot;);
  background-repeat: no-repeat;
}
.nice-form-group &gt; input[type=&quot;range&quot;] {
  -webkit-appearance: none;
  width: 100%;
  cursor: pointer;
}
.nice-form-group &gt; input[type=&quot;range&quot;]:focus {
  outline: none;
}
.nice-form-group &gt; input[type=&quot;range&quot;]::-webkit-slider-runnable-track {
  width: 100%;
  height: var(--nf-slider-track-height);
  background: var(--nf-slider-track-background);
  border-radius: var(--nf-slider-track-border-radius);
}
.nice-form-group &gt; input[type=&quot;range&quot;]::-moz-range-track {
  width: 100%;
  height: var(--nf-slider-track-height);
  background: var(--nf-slider-track-background);
  border-radius: var(--nf-slider-track-border-radius);
}
.nice-form-group &gt; input[type=&quot;range&quot;]::-webkit-slider-thumb {
  height: var(--nf-slider-thumb-size);
  width: var(--nf-slider-thumb-size);
  border-radius: var(--nf-slider-thumb-size);
  background: var(--nf-slider-thumb-background);
  border: 0;
  border: var(--nf-slider-thumb-border-width) solid var(--nf-slider-thumb-border-color);
  -webkit-appearance: none;
  appearance: none;
  margin-top: calc(var(--nf-slider-track-height) * 0.5 - var(--nf-slider-thumb-size) * 0.5);
}
.nice-form-group &gt; input[type=&quot;range&quot;]::-moz-range-thumb {
  height: var(--nf-slider-thumb-size);
  width: var(--nf-slider-thumb-size);
  border-radius: var(--nf-slider-thumb-size);
  background: var(--nf-slider-thumb-background);
  border: 0;
  border: var(--nf-slider-thumb-border-width) solid var(--nf-slider-thumb-border-color);
  -moz-appearance: none;
  appearance: none;
  box-sizing: border-box;
}
.nice-form-group &gt; input[type=&quot;range&quot;]:focus::-webkit-slider-thumb {
  box-shadow: 0 0 0 var(--nf-slider-thumb-border-focus-width) var(--nf-slider-thumb-background);
}
.nice-form-group &gt; input[type=&quot;range&quot;]:focus::-moz-range-thumb {
  box-shadow: 0 0 0 var(--nf-slider-thumb-border-focus-width) var(--nf-slider-thumb-background);
}
.nice-form-group &gt; input[type=&quot;color&quot;] {
  border: var(--nf-input-border-width) solid var(--nf-input-border-color);
  border-bottom-width: var(--nf-input-border-bottom-width);
  height: calc(var(--nf-input-size) * 2);
  border-radius: var(--nf-input-border-radius);
  padding: calc(var(--nf-input-border-width) * 2);
}
.nice-form-group &gt; input[type=&quot;color&quot;]:focus {
  outline: none;
  border-color: var(--nf-input-focus-border-color);
}
.nice-form-group &gt; input[type=&quot;color&quot;]::-webkit-color-swatch-wrapper {
  padding: 5%;
}
.nice-form-group &gt; input[type=&quot;color&quot;]::-moz-color-swatch {
  border-radius: calc(var(--nf-input-border-radius) / 2);
  border: none;
}
.nice-form-group &gt; input[type=&quot;color&quot;]::-webkit-color-swatch {
  border-radius: calc(var(--nf-input-border-radius) / 2);
  border: none;
}
.nice-form-group &gt; input[type=&quot;number&quot;] {
  width: auto;
}
.nice-form-group &gt; input[type=&quot;date&quot;],
.nice-form-group &gt; input[type=&quot;month&quot;],
.nice-form-group &gt; input[type=&quot;week&quot;] {
  min-width: 14em;
  background-image: url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;16&#39; height=&#39;16&#39; viewBox=&#39;0 0 24 24&#39; fill=&#39;none&#39; stroke=&#39;%236B7280&#39; stroke-width=&#39;2&#39; stroke-linecap=&#39;round&#39; stroke-linejoin=&#39;round&#39; class=&#39;feather feather-calendar&#39;%3E%3Crect x=&#39;3&#39; y=&#39;4&#39; width=&#39;18&#39; height=&#39;18&#39; rx=&#39;2&#39; ry=&#39;2&#39;/%3E%3Cpath d=&#39;M16 2v4M8 2v4M3 10h18&#39;/%3E%3C/svg%3E&quot;);
}
.nice-form-group &gt; input[type=&quot;time&quot;] {
  min-width: 6em;
  background-image: url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;16&#39; height=&#39;16&#39; viewBox=&#39;0 0 24 24&#39; fill=&#39;none&#39; stroke=&#39;%236B7280&#39; stroke-width=&#39;2&#39; stroke-linecap=&#39;round&#39; stroke-linejoin=&#39;round&#39; class=&#39;feather feather-clock&#39;%3E%3Ccircle cx=&#39;12&#39; cy=&#39;12&#39; r=&#39;10&#39;/%3E%3Cpath d=&#39;M12 6v6l4 2&#39;/%3E%3C/svg%3E&quot;);
}
.nice-form-group &gt; input[type=&quot;date&quot;],
.nice-form-group &gt; input[type=&quot;month&quot;],
.nice-form-group &gt; input[type=&quot;time&quot;],
.nice-form-group &gt; input[type=&quot;week&quot;] {
  background-position: right calc(var(--nf-input-size) * 0.75) bottom 50%;
  background-repeat: no-repeat;
  background-size: var(--nf-input-size);
  width: auto;
}
.nice-form-group &gt; input[type=&quot;date&quot;]::-webkit-calendar-picker-indicator,
.nice-form-group &gt; input[type=&quot;date&quot;]::-webkit-inner-spin-button,
.nice-form-group &gt; input[type=&quot;month&quot;]::-webkit-calendar-picker-indicator,
.nice-form-group &gt; input[type=&quot;month&quot;]::-webkit-inner-spin-button,
.nice-form-group &gt; input[type=&quot;time&quot;]::-webkit-calendar-picker-indicator,
.nice-form-group &gt; input[type=&quot;time&quot;]::-webkit-inner-spin-button,
.nice-form-group &gt; input[type=&quot;week&quot;]::-webkit-calendar-picker-indicator,
.nice-form-group &gt; input[type=&quot;week&quot;]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  cursor: pointer;
  opacity: 0;
}
@-moz-document url-prefix() {
  .nice-form-group &gt; input[type=&quot;date&quot;],
  .nice-form-group &gt; input[type=&quot;month&quot;],
  .nice-form-group &gt; input[type=&quot;time&quot;],
  .nice-form-group &gt; input[type=&quot;week&quot;] {
    min-width: auto;
    width: auto;
    background-image: none;
  }
}
.nice-form-group &gt; textarea {
  height: auto;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;],
.nice-form-group &gt; input[type=&quot;radio&quot;] {
  width: var(--nf-input-size);
  height: var(--nf-input-size);
  padding: inherit;
  margin: 0;
  display: inline-block;
  vertical-align: top;
  border-radius: calc(var(--nf-input-border-radius) / 2);
  border-width: var(--nf-input-border-width);
  cursor: pointer;
  background-position: 50%;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]:focus:not(:checked),
.nice-form-group &gt; input[type=&quot;radio&quot;]:focus:not(:checked) {
  border: var(--nf-input-border-width) solid var(--nf-input-focus-border-color);
  outline: none;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]:hover,
.nice-form-group &gt; input[type=&quot;radio&quot;]:hover {
  border: var(--nf-input-border-width) solid var(--nf-input-focus-border-color);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;] + label,
.nice-form-group &gt; input[type=&quot;radio&quot;] + label {
  display: inline-block;
  margin-bottom: 0;
  padding-left: calc(var(--nf-input-size) / 2.5);
  font-weight: 400;
  -webkit-user-select: none;
  user-select: none;
  cursor: pointer;
  max-width: calc(100% - var(--nf-input-size) * 2);
  line-height: normal;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;] + label &gt; small,
.nice-form-group &gt; input[type=&quot;radio&quot;] + label &gt; small {
  margin-top: calc(var(--nf-input-size) / 4);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;]:checked {
  background: url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;20&#39; height=&#39;20&#39; viewBox=&#39;0 0 24 24&#39; fill=&#39;none&#39; stroke=&#39;%23FFF&#39; stroke-width=&#39;3&#39; stroke-linecap=&#39;round&#39; stroke-linejoin=&#39;round&#39; class=&#39;feather feather-check&#39;%3E%3Cpath d=&#39;M20 6L9 17l-5-5&#39;/%3E%3C/svg%3E&quot;)
    no-repeat 50%/85%;
  background-color: var(--nf-input-focus-border-color);
  border-color: var(--nf-input-focus-border-color);
}
.nice-form-group &gt; input[type=&quot;radio&quot;] {
  border-radius: 100%;
}
.nice-form-group &gt; input[type=&quot;radio&quot;]:checked {
  background-color: var(--nf-input-focus-border-color);
  border-color: var(--nf-input-focus-border-color);
  box-shadow: inset 0 0 0 3px #fff;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;].switch {
  width: var(--switch-width);
  height: var(--switch-height);
  border-radius: var(--switch-height);
  position: relative;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;].switch:after {
  background: var(--nf-input-border-color);
  border-radius: var(--switch-orb-size);
  height: var(--switch-orb-size);
  left: var(--switch-orb-offset);
  position: absolute;
  top: 50%;
  -webkit-transform: translateY(-50%);
  transform: translateY(-50%);
  width: var(--switch-orb-size);
  content: &quot;&quot;;
  transition: all 0.2s ease-out;
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;].switch + label {
  margin-top: calc(var(--switch-height) / 8);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;].switch:checked {
  background: none;
  background-position: 0 0;
  background-color: var(--nf-input-focus-border-color);
}
.nice-form-group &gt; input[type=&quot;checkbox&quot;].switch:checked:after {
  -webkit-transform: translateY(-50%) translateX(calc(var(--switch-width) / 2 - var(--switch-orb-offset)));
  transform: translateY(-50%) translateX(calc(var(--switch-width) / 2 - var(--switch-orb-offset)));
  background: #fff;
}
.nice-form-group &gt; input[type=&quot;file&quot;] {
  background: rgba(0, 0, 0, 0.025);
  padding: var(--nf-input-size);
  display: block;
  width: 100%;
  border-radius: var(--nf-input-border-radius);
  border: 1px dashed var(--nf-input-border-color);
  outline: none;
  cursor: pointer;
}
.nice-form-group &gt; input[type=&quot;file&quot;]:focus,
.nice-form-group &gt; input[type=&quot;file&quot;]:hover {
  border-color: var(--nf-input-focus-border-color);
}
.nice-form-group &gt; input[type=&quot;file&quot;]::file-selector-button {
  background: var(--nf-input-focus-border-color);
  border: 0;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  padding: 0.5rem;
  border-radius: var(--nf-input-border-radius);
  color: #fff;
  margin-right: 1rem;
  outline: none;
  font-family: var(--nf-input-font-family);
  cursor: pointer;
}
.nice-form-group &gt; input[type=&quot;file&quot;]::-webkit-file-upload-button {
  background: var(--nf-input-focus-border-color);
  border: 0;
  -webkit-appearance: none;
  appearance: none;
  padding: 0.5rem;
  border-radius: var(--nf-input-border-radius);
  color: #fff;
  margin-right: 1rem;
  outline: none;
  font-family: var(--nf-input-font-family);
  cursor: pointer;
}
.nice-form-group &gt; select {
  background-image: url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;16&#39; height=&#39;16&#39; viewBox=&#39;0 0 24 24&#39; fill=&#39;none&#39; stroke=&#39;%236B7280&#39; stroke-width=&#39;2&#39; stroke-linecap=&#39;round&#39; stroke-linejoin=&#39;round&#39; class=&#39;feather feather-chevron-down&#39;%3E%3Cpath d=&#39;M6 9l6 6 6-6&#39;/%3E%3C/svg%3E&quot;);
  background-position: right calc(var(--nf-input-size) * 0.75) bottom 50%;
  background-repeat: no-repeat;
  background-size: var(--nf-input-size);
}
*,
:after,
:before {
  box-sizing: inherit;
}
html {
  font-size: 16px;
  box-sizing: border-box;
}
body {
  background: #f3f0e7;
  font-family: Roboto, sans-serif;
  color: #4b5563;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
.demo-page {
  margin: 0 auto;
  display: -webkit-flex;
  display: flex;
  max-width: 55em;
}
.demo-page .demo-page-navigation {
  width: 18em;
  padding: 2em 1em;
}
@media only screen and (max-width: 750px) {
  .demo-page .demo-page-navigation {
    display: none;
  }
}
.demo-page .demo-page-navigation nav {
  position: -webkit-sticky;
  position: sticky;
  top: 2em;
  background: #fff;
  padding: 0.5em;
  border-radius: 0.75rem;
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.demo-page .demo-page-navigation a {
  display: -webkit-flex;
  display: flex;
  padding: 0.75em 1em;
  text-decoration: none;
  border-radius: 0.25em;
  color: #374151;
  -webkit-align-items: center;
  align-items: center;
}
.demo-page .demo-page-navigation a:hover {
  background: #f3f4f6;
}
.demo-page .demo-page-navigation a svg {
  width: 1.25em;
  height: 1.25em;
  margin-right: 1em;
  color: #1f2937;
}
.demo-page .demo-page-content {
  padding: 2em 1em;
  max-width: 100%;
}
@media only screen and (min-width: 750px) {
  .demo-page .demo-page-content {
    width: calc(100% - 18em);
  }
}
footer {
  text-align: center;
  margin: 2.5em 0;
}
.href-target {
  position: absolute;
  top: -2em;
}
.to-repo,
.to-reset {
  display: -webkit-inline-flex;
  display: inline-flex;
  background: #24292e;
  color: #fff;
  border-radius: 5px;
  padding: 0.5em 1em;
  text-decoration: none;
  -webkit-align-items: center;
  align-items: center;
  transition: background 0.2s ease-out;
}
.to-repo:hover,
.to-reset:hover {
  background: #000;
}
.to-repo svg,
.to-reset svg {
  width: 1.125rem;
  height: 1.125rem;
  margin-right: 0.75em;
}
.to-reset {
  background: #3b4ce2;
}
.to-reset:hover {
  background: #2538df;
}
section {
  background: #fff;
  padding: 2em;
  border-radius: 0.75rem;
  line-height: 1.6;
  overflow: hidden;
  margin-bottom: 2rem;
  position: relative;
  font-size: 0.875rem;
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
section h1 {
  font-weight: 500;
  font-size: 1.25rem;
  color: #000;
  margin-bottom: 0.75rem;
}
section h1 svg {
  width: 1em;
  height: 1em;
  display: inline-block;
  vertical-align: -10%;
  margin-right: 0.25em;
}
section h1.package-name {
  font-size: 2rem;
  margin-bottom: 0.75rem;
  margin-top: -0.5rem;
}
section strong {
  font-weight: 500;
  color: #000;
}
section p {
  margin: 0.5rem 0 1.5rem;
}
section p a {
  text-decoration: none;
  font-weight: 500;
  color: #3b4ce2;
}
section p:last-child {
  margin-bottom: 0;
}
section code {
  font-weight: 500;
  font-family: Consolas, monaco, monospace;
  position: relative;
  z-index: 1;
  margin: 0 2px;
  background: #f3f4f4;
  content: &quot;&quot;;
  border-radius: 3px;
  padding: 2px 5px;
  white-space: nowrap;
}
section ul {
  margin-top: 0.5em;
  padding-left: 1em;
  list-style-type: disc;
}
details {
  background: #f1f1f1;
  margin: 2em -2em -2em;
  padding: 1.5em 2em;
}
details .gist {
  margin-top: 1.5em;
}
details .toggle-code {
  display: inline-block;
  padding: 0.5em 1em;
  border-radius: 5px;
  font-size: 0.875rem;
  background: #10b981;
  top: 1em;
  right: 1em;
  color: #fff;
  font-weight: 500;
  -webkit-user-select: none;
  user-select: none;
  cursor: pointer;
}
details .toggle-code:hover {
  background: #0ea271;
}
details .toggle-code svg {
  display: inline-block;
  vertical-align: -15%;
  margin-right: 0.25em;
}
details summary {
  outline: none;
  list-style-type: none;
}
details summary::marker {
  display: none;
}
details summary::-webkit-details-marker {
  display: none;
}
</code></pre>
<h3 id="checkpoint">CheckPoint.</h3>
<p><code>옵셔널체이닝</code> : .? 앞의 내용들을 검사하여 undifined라면 undefined를 반환(오류방지, 유사 try catch)
<code>[^A-Z0-9+_.]</code> : 정규화식
<code>return;</code> 으로 다음 함수가 진행되기전에 멈추기.
<code>checked</code> radio타입에 checked 속성을 주입하여 undefind 방지하기.
<code>label for</code> lavel 태그에 for을 사용하여 input태그의 id값과 동일하게 맞추어 label을 선택했을 때에도 작동할 수 있도록 사용자 편의성 개선.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java]Consolo출력 색 입히기]]></title>
            <link>https://velog.io/@_error/JavaConsolo%EC%B6%9C%EB%A0%A5-%EC%83%89-%EC%9E%85%ED%9E%88%EA%B8%B0</link>
            <guid>https://velog.io/@_error/JavaConsolo%EC%B6%9C%EB%A0%A5-%EC%83%89-%EC%9E%85%ED%9E%88%EA%B8%B0</guid>
            <pubDate>Wed, 16 Oct 2024 01:15:18 GMT</pubDate>
            <description><![CDATA[<p> <code>ANSI escape codes</code> 사용하여 변수에 색상 코드를 대입한 뒤 사용
 (아래 코드 제공)</p>
<p> 사용예시</p>
<blockquote>
<p> System.out.println(<strong><span style="color: red"><code>ANSI_RED_BACKGROUND</code></span></strong> + &quot;This text is red!&quot; + <strong><span style="color: red"><code>RESET</code></span></strong>);
  System.out.print(<strong><span style="color: red"><code>YELLOW_BOLD_BRIGHT</code> </span></strong>+ &quot;complete!&quot; + <strong><span style="color: red"><code>RESET</code></span></strong>);</p>
</blockquote>
<p><span style="color: red"><strong>RESET</strong></span> 을 사용하지 않으면 뒤에 오는 내용들까지 다 적용되니 <span style="color: red"><strong>RESET</strong></span> (<span style="color: red"><code>String RESET = &quot;\033[0m&quot;</code></span>)을 통해 적용 범위를 통제할 것.</p>
<pre><code class="language-java">public class ConsoleColors {

    // Reset
    public static final String RESET = &quot;\033[0m&quot;;  // Text Reset

    // backgroudColor
    public static final String ANSI_BLACK_BACKGROUND = &quot;\u001B[40m&quot;;
    public static final String ANSI_RED_BACKGROUND = &quot;\u001B[41m&quot;;
    public static final String ANSI_GREEN_BACKGROUND = &quot;\u001B[42m&quot;;
    public static final String ANSI_YELLOW_BACKGROUND = &quot;\u001B[43m&quot;;
    public static final String ANSI_BLUE_BACKGROUND = &quot;\u001B[44m&quot;;
    public static final String ANSI_PURPLE_BACKGROUND = &quot;\u001B[45m&quot;;
    public static final String ANSI_CYAN_BACKGROUND = &quot;\u001B[46m&quot;;
    public static final String ANSI_WHITE_BACKGROUND = &quot;\u001B[47m&quot;;

    // Regular Colors
    public static final String BLACK = &quot;\033[0;30m&quot;;   // BLACK
    public static final String RED = &quot;\033[0;31m&quot;;     // RED
    public static final String GREEN = &quot;\033[0;32m&quot;;   // GREEN
    public static final String YELLOW = &quot;\033[0;33m&quot;;  // YELLOW
    public static final String BLUE = &quot;\033[0;34m&quot;;    // BLUE
    public static final String PURPLE = &quot;\033[0;35m&quot;;  // PURPLE
    public static final String CYAN = &quot;\033[0;36m&quot;;    // CYAN
    public static final String WHITE = &quot;\033[0;37m&quot;;   // WHITE

    // Bold
    public static final String BLACK_BOLD = &quot;\033[1;30m&quot;;  // BLACK
    public static final String RED_BOLD = &quot;\033[1;31m&quot;;    // RED
    public static final String GREEN_BOLD = &quot;\033[1;32m&quot;;  // GREEN
    public static final String YELLOW_BOLD = &quot;\033[1;33m&quot;; // YELLOW
    public static final String BLUE_BOLD = &quot;\033[1;34m&quot;;   // BLUE
    public static final String PURPLE_BOLD = &quot;\033[1;35m&quot;; // PURPLE
    public static final String CYAN_BOLD = &quot;\033[1;36m&quot;;   // CYAN
    public static final String WHITE_BOLD = &quot;\033[1;37m&quot;;  // WHITE

    // Underline
    public static final String BLACK_UNDERLINED = &quot;\033[4;30m&quot;;  // BLACK
    public static final String RED_UNDERLINED = &quot;\033[4;31m&quot;;    // RED
    public static final String GREEN_UNDERLINED = &quot;\033[4;32m&quot;;  // GREEN
    public static final String YELLOW_UNDERLINED = &quot;\033[4;33m&quot;; // YELLOW
    public static final String BLUE_UNDERLINED = &quot;\033[4;34m&quot;;   // BLUE
    public static final String PURPLE_UNDERLINED = &quot;\033[4;35m&quot;; // PURPLE
    public static final String CYAN_UNDERLINED = &quot;\033[4;36m&quot;;   // CYAN
    public static final String WHITE_UNDERLINED = &quot;\033[4;37m&quot;;  // WHITE

    // Background
    public static final String BLACK_BACKGROUND = &quot;\033[40m&quot;;  // BLACK
    public static final String RED_BACKGROUND = &quot;\033[41m&quot;;    // RED
    public static final String GREEN_BACKGROUND = &quot;\033[42m&quot;;  // GREEN
    public static final String YELLOW_BACKGROUND = &quot;\033[43m&quot;; // YELLOW
    public static final String BLUE_BACKGROUND = &quot;\033[44m&quot;;   // BLUE
    public static final String PURPLE_BACKGROUND = &quot;\033[45m&quot;; // PURPLE
    public static final String CYAN_BACKGROUND = &quot;\033[46m&quot;;   // CYAN
    public static final String WHITE_BACKGROUND = &quot;\033[47m&quot;;  // WHITE

    // High Intensity
    public static final String BLACK_BRIGHT = &quot;\033[0;90m&quot;;  // BLACK
    public static final String RED_BRIGHT = &quot;\033[0;91m&quot;;    // RED
    public static final String GREEN_BRIGHT = &quot;\033[0;92m&quot;;  // GREEN
    public static final String YELLOW_BRIGHT = &quot;\033[0;93m&quot;; // YELLOW
    public static final String BLUE_BRIGHT = &quot;\033[0;94m&quot;;   // BLUE
    public static final String PURPLE_BRIGHT = &quot;\033[0;95m&quot;; // PURPLE
    public static final String CYAN_BRIGHT = &quot;\033[0;96m&quot;;   // CYAN
    public static final String WHITE_BRIGHT = &quot;\033[0;97m&quot;;  // WHITE

    // Bold High Intensity
    public static final String BLACK_BOLD_BRIGHT = &quot;\033[1;90m&quot;; // BLACK
    public static final String RED_BOLD_BRIGHT = &quot;\033[1;91m&quot;;   // RED
    public static final String GREEN_BOLD_BRIGHT = &quot;\033[1;92m&quot;; // GREEN
    public static final String YELLOW_BOLD_BRIGHT = &quot;\033[1;93m&quot;;// YELLOW
    public static final String BLUE_BOLD_BRIGHT = &quot;\033[1;94m&quot;;  // BLUE
    public static final String PURPLE_BOLD_BRIGHT = &quot;\033[1;95m&quot;;// PURPLE
    public static final String CYAN_BOLD_BRIGHT = &quot;\033[1;96m&quot;;  // CYAN
    public static final String WHITE_BOLD_BRIGHT = &quot;\033[1;97m&quot;; // WHITE

    // High Intensity backgrounds
    public static final String BLACK_BACKGROUND_BRIGHT = &quot;\033[0;100m&quot;;// BLACK
    public static final String RED_BACKGROUND_BRIGHT = &quot;\033[0;101m&quot;;// RED
    public static final String GREEN_BACKGROUND_BRIGHT = &quot;\033[0;102m&quot;;// GREEN
    public static final String YELLOW_BACKGROUND_BRIGHT = &quot;\033[0;103m&quot;;// YELLOW
    public static final String BLUE_BACKGROUND_BRIGHT = &quot;\033[0;104m&quot;;// BLUE
    public static final String PURPLE_BACKGROUND_BRIGHT = &quot;\033[0;105m&quot;; // PURPLE
    public static final String CYAN_BACKGROUND_BRIGHT = &quot;\033[0;106m&quot;;  // CYAN
    public static final String WHITE_BACKGROUND_BRIGHT = &quot;\033[0;107m&quot;;   // WHITE
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL 기초 문법]]></title>
            <link>https://velog.io/@_error/SQL</link>
            <guid>https://velog.io/@_error/SQL</guid>
            <pubDate>Tue, 20 Aug 2024 06:41:28 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>📌 <strong><code>SQL</code> 기본 문법 및 단어정리</strong></p>
</blockquote>
<hr>
<p><strong><code>SELECT</code></strong>    열_이름</p>
<p><strong><code>FROM</code></strong>     테이블_이름</p>
<p><strong><code>WHERE</code></strong>     조건식</p>
<p><strong><code>GROUP BY</code></strong>     열_이름</p>
<p><strong><code>HAVING</code></strong>     조건식</p>
<p><strong><code>ORDER BY</code></strong>     열_이름</p>
<p><strong><code>LIMIT</code></strong>     숫자</p>
<hr>
<blockquote>
<h2 id="⚙-연산자-종류">⚙ 연산자 종류</h2>
</blockquote>
<p><strong>1. 관계  연산자</strong></p>
<p><code>&gt;</code> , <code>&lt;</code> , <code>&gt;=</code> , <code>&lt;=</code> , <code>=</code> </p>
<hr>
<p><strong>2. 논리  연산자</strong>
<BR>
<strong><code>AND</code></strong> : 두 조건이 모두 만족하면 조회</p>
<p><span style="color: #FF0000"><code>SELECT</code></span> mem_name,height, mem_number
<span style="color: #FF0000"><code>FROM</code></span> member
<span style="color: #FF0000"><code>WHERE</code></span> height &gt;= 165 <span style="color: #FF0000"><code>AND</code></span> mem_number &gt; 6;</p>
<hr>
<p><strong><code>OR</code></strong> : 둘 중 하나라도 만족하면 조회</p>
<p><span style="color: #FF0000"><code>SELECT</code></span> mem_name,height, mem_number
<span style="color: #FF0000"><code>FROM</code></span> member
<span style="color: #FF0000"><code>WHERE</code></span> height &gt;= 165 <span style="color: #FF0000"><code>OR</code></span> mem_number &gt; 6;</p>
<hr>
<p><strong><code>BETWEEN ~AND</code></strong> : 범위 ~ 를 사용할 때 이용</p>
<p><span style="color: #FF0000"><code>SELECT</code></span> mem_name,height, mem_number
<span style="color: #FF0000"><code>FROM</code></span> member
<span style="color: #FF0000"><code>WHERE</code></span> height <span style="color: #FF0000"><code>BETWEEN</code></span> 163 <span style="color: #FF0000"><code>AND</code> </span> 165;</p>
<hr>
<p><strong><code>IN</code></strong> : in내에 들어있는 것들 중 하나라도 존재하면 조회.</p>
<p><span style="color: #FF0000"><code>SELECT</code></span> mem_name, addr
<span style="color: #FF0000"><code>FROM</code></span> member
<span style="color: #FF0000"><code>WHERE</code></span> addr <span style="color: #FF0000"><code>IN</code></span> (&#39;경기&#39;, &#39;전남&#39;, &#39;경남&#39;);</p>
<hr>
<p><strong><code>LIKE</code></strong> : 서울%, %민국 와 같이 %을 기준으로 앞 또는 뒤에 오는 문자열을 조회</p>
<p><span style="color: #FF0000"><code>SELECT</code></span> *
<span style="color: #FF0000"><code>FROM</code></span> member
<span style="color: #FF0000"><code>WHERE</code></span> mem_name <span style="color: #FF0000"><code>LIKE</code></span> &#39;우%&#39;;</p>
<hr>
<p><strong><code>_</code></strong> : 글자와 매치하는 자료를 조회</p>
<p><span style="color: #FF0000"><code>SELECT</code></span> *
<span style="color: #FF0000"><code>FROM</code></span> member
<span style="color: #FF0000"><code>WHERE</code></span> mem_name <span style="color: #FF0000"><code>LIKE</code></span> &#39;__핑크&#39;;</p>
<hr>
<p><strong>3. ** **결과를 정렬하는 : <code>ORDER BY</code></strong> </p>
<p><span style="color: #FF0000"><code>SELECT</code></span> mem_id, mem_name, debut_date
<span style="color: #FF0000"><code>FROM</code></span> member
<span style="color: #FF0000"><code>ORDER BY</code></span> debut_date;</p>
<p>  debut_date(데뷔 일자)를 늦은 순서대로 하려면 <code>DESC</code>(Descending)을 붙이면 됨. 
  <br>
**  오름차순 <code>ASC</code>(Ascending) 내림차순<code>DESC</code>(Descending)**</p>
<p>  <span style="color: #FF0000"><code>SELECT</code></span> mem_id, mem_name, debut_date
<span style="color: #FF0000"><code>FROM</code></span> member
<span style="color: #FF0000"><code>ORDER BY</code></span> debut_date <span style="color: #FF0000"><code>DESC</code></span>, mem_id <span style="color: #FF0000"><code>ASC</code></span> ;</p>
<p>** 코드 분석 : debut_date 는 내림차순 , mem_id 는 오름차순 정렬.**</p>
<hr>
<p><strong>4. 출력의 개수를 제한하는 <code>LIMIT</code></strong></p>
<pre><code>&lt;span style=&quot;color: #FF0000&quot;&gt;`SELECT`&lt;/span&gt; mem_name, height</code></pre><p><span style="color: #FF0000"><code>FROM</code></span> member
<span style="color: #FF0000"><code>ORDER BY</code></span> height <span style="color: #FF0000"><code>DESC</code></span> <span style="color: #FF0000"><code>LIMIT</code></span> 3, 2 ;</p>
<p>  ** 코드 분석 : height를 내림차순 즉, 큰 순으로 정렬하되 3번째부터 2건만 조회.**</p>
<hr>
<p>  <strong>5. 중복을 제거하는 <code>DISTINCT</code></strong>
  <span style="color: #FF0000"><code>SELECT</code></span> <span style="color: #FF0000"><code>DISTINCT</code></span> addr
<span style="color: #FF0000"><code>FROM</code></span> member</p>
<p>   ** 코드 분석 : addr 열의 조회되는 중복된 데이터를 모두 제거.**</p>
<hr>
<p>  <strong>6. 데이터를 그룹화하는 <code>GROUP BY</code></strong> (집계함수와 주로 사용)</p>
<p> <code>SUM()</code> : 합계를 구합니다.
  <code>AVG()</code> : 평균을 구합니다.
  <code>MIN()</code>: 최소값을 구합니다.
  <code>MAX()</code> : 최대값을 구합니다.
  <code>COUNT()</code>: 행의 개수를 셉니다.
  <code>COUNT(DISTINCT)</code>:행의 개수를 세며 중복은 1개만 인정됩니다.</p>
<p>   <span style="color: #FF0000"><code>SELECT</code></span> member_id <span style="color: #FF0000"><code>SUM()</code></span> 
<span style="color: #FF0000"><code>FROM</code></span> buy <span style="color: #FF0000"><code>GROUP BY</code></span> member;</p>
<p><span style="color: #FF0000"><code>SELECT</code></span> member_id &quot;회원 아이디&quot;, <span style="color: #FF0000"><code>SUM(price * amoount)</code> </span>&quot;총구매액&quot; 
<span style="color: #FF0000"><code>FROM</code></span> buy <span style="color: #FF0000"><code>GROUP BY</code></span> mem_id;</p>
<hr>
<p>  <strong>7. WHERE절 대신 사용하는 <code>GROUP BY</code> 의 친구 <code>HAVING</code></strong> 
(HAVING 절은 꼭 GROUP BY 절 다음에 나와야한다.)
  <em>집계 함수에 대해서 조건을 제한하는 것.</em></p>
<p>  <span style="color: #FF0000"><code>SELECT</code></span> member_id &quot;회원 아이디&quot;, <span style="color: #FF0000"><code>SUM(price * amoount)</code> </span>&quot;총구매액&quot; 
<span style="color: #FF0000"><code>FROM</code></span> buy <span style="color: #FF0000"><code>GROUP BY</code></span> mem_id;
<span style="color: #FF0000"><code>HAVING</code> <code>SUM(price * amoount) &gt; 10</code> </span></p>
<p><strong>지금까지 다룬 내용은 쿼리에서 가장 많이 쓰이는 SELECT 문의 문법이고
  고급 문법이나 함수 등 여러 활용 방안이 많다.</strong></p>
<blockquote>
<p><strong>참고하기 좋은 사이트</strong><BR>
  <a href="https://suy379.tistory.com/107">https://suy379.tistory.com/107</a> - 함수정리
  <a href="https://suy379.tistory.com/106">https://suy379.tistory.com/106</a> - 서브쿼리 사용법
  <a href="https://mangkyu.tistory.com/25#google_vignette">https://mangkyu.tistory.com/25#google_vignette</a> - 함수 및 고급문법</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[조건문과 반복문 (2)]]></title>
            <link>https://velog.io/@_error/%EC%A1%B0%EA%B1%B4%EB%AC%B8%EA%B3%BC-%EB%B0%98%EB%B3%B5%EB%AC%B8-2</link>
            <guid>https://velog.io/@_error/%EC%A1%B0%EA%B1%B4%EB%AC%B8%EA%B3%BC-%EB%B0%98%EB%B3%B5%EB%AC%B8-2</guid>
            <pubDate>Mon, 19 Aug 2024 05:13:44 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>✅ <strong><code>for</code>문</strong><img src="https://velog.velcdn.com/images/_error/post/798b3fdc-8ad0-40f4-91a1-df16799e5ef6/image.png" alt=""></p>
</blockquote>
<p><strong>반복된 횟수를 알고있을 경우 사용하기 적합한 반복문</strong></p>
<hr>
<p>&quot;<strong><code>for</code></strong>&quot;라는 예약어를 만나는 경우 ( ) 안에 있는 조건이 <strong>참이면 반복실행</strong>하겠다. 라는 뜻</p>
<p>(1)</p>
<p><code>for</code>(<span style='background-color: #dcffe4'>`<strong>초기화</strong>;</span> 조건식; 증감식;) {
 // 조건식이 참일 때 수행될 문장들 
}</p>
<h3 id="초기화는">초기화는</h3>
<p><span style='background-color: #dcffe4'><strong>초기화</strong>;</span>
변수를 초기화하는 부분이며 처음에 기준값이 된다.</p>
<h3 id="조건식은">조건식은</h3>
<p><code>for</code>(초기화; <span style='background-color: #ffdce0'><strong>조건식</strong>;</span> 증감식;) {
 // 조건식이 참일 때 수행될 문장들 
}</p>
<p><code>for</code>의 뜻이 &#39;~하는 동안&#39; 이므로 조건식이 <strong>참인 동안 반복</strong>을 계속한다.
예를 들어 <strong>(int i=1; <span style='background-color: #ffdce0'> i&lt;10;</span> i++)</strong> 라고 가정한다면 i는 1을 초기값(<strong><code>i=1</code></strong>)으로 가지며 i가 10 보다 낮으면(<strong><code>i&lt;10</code></strong>) 계속 반복하겠다 라는 뜻이다.</p>
<h3 id="증감식은">증감식은</h3>
<p><code>for</code>(초기화; 조건식; <span style='background-color: #f5f0ff'><strong>증감식;</strong></span> ) {
 // 조건식이 참일 때 수행될 문장들 
}</p>
<p>반복문에서 초기화에 사용한 변수를 증가 또는 감소시키는 식이다.
                                                                                                                                       처음 초기화시킨 <code>i=1</code> 의 변수 값을 <code>++</code>(증가) 점진적으로 증가시켜 결국 조건이 거짓이 되어 (i가 10보다 커졌을 때) <code>for문</code>을 벗어나게 된다.</p>
<pre><code>for(int i =1; i&lt;=10; i++) { ... } // 1부터 10까지 1씩 증가
for(int i =1; i&lt;=10; i--) { ... } // 1부터 10까지 1씩 감소
for(int i =1; i&lt;=10; i+= 2) { ... } // 1부터 10까지 2씩 증가
for(int i =1; i&lt;=10; i*= 3) { ... } // 1부터 10까지 3배씩 증가</code></pre><p><code>for( )</code> <strong>{</strong></p>
<p><strong>}</strong> <code>for문</code>에서 이 코드블럭( {} )이 한 범위이다. 그렇기 때문에 <code>for문</code>의 범위 내에서 사용된 지역변수는 <code>for문</code>이 종료되는 순간 소멸한다. <span style='background-color: #fff5b1'> <strong>또한 범위가 끝나기 전에 만나는 코드들은 모두 실행시키고 다시 조건식으로 올라온다는 점을 꼭 기억하자</strong> </span>.</p>
<h3 id="✏️구구단-2단에서-9단까지-생성하기">✏️구구단 2단에서 9단까지 생성하기.</h3>
<pre><code>// 구구단 example.

        for(int i= 2; i &lt; 10; i++){
                System.out.println( &quot;=== &quot; + i + &quot;단 ===&quot; );
            for(int j= 1; j &lt; 10; j++){
                int result = i*j;
                System.out.println( i + &quot; * &quot; + j + &quot; = &quot; + result);
            }
        }
</code></pre><h3 id="👉첫번째-example-코드흐름">👉첫번째 example 코드흐름</h3>
<ol>
<li><code>for</code>(예약어)가 읽혀 ( ) 안에 식들을 참인지 거짓인지 확인함.</li>
<li><code>int i = 2;</code> i 라는 변수에 2 라는 값을 초기값으로 셋팅함.</li>
<li><code>i &lt; 10</code> 라는 조건에 부합함으로 (2 &lt; 10) 코드블럭실행 { }</li>
<li>코드블럭 실행중 한 번 더 <code>for</code>등장 동일하게 조건을 확인하고 진행</li>
<li>두 번째 <code>for문</code>에서는   System.out.println( i + &quot; * &quot; + j + &quot; = &quot; + result); } 를 마지막으로 코드블럭이 닫힌다.  <span style='background-color: #fff5b1'> <strong>코드블럭이 닫히기 전까지 모든 코드를 실행시켰고 더 이상 실행시킬 코드가 존재하지 않으니 다시 반복하기 위해 두 번째 <code>for문</code>으로 올라간다.</strong></span></li>
<li>두 번째 <code>for문</code>을 반복에 반복을 거쳐 조건이 부합하지 않을 경우 두 번째 for문을 탈출하게 되고 탈출한 뒤엔 원래 진행하던 첫 번째 for문의 흐름을 이어탄다.</li>
</ol>
<h3 id="-------------------------------------------------------------------------------">-------------------------------------------------------------------------------</h3>
<h3 id="✏️1부터-10까지의-합을-구한-뒤-평균-구하기">✏️1부터 10까지의 합을 구한 뒤 평균 구하기.</h3>
<pre><code>// 1부터 10까지의 합을 구한 뒤 평균을 구하는 Example
        int sum = 0; // 전역변수를 선언.
        for(int i=1; i&lt;11; i++){
            sum = sum + i; 
            System.out.println(sum);
        }
        int avg = sum / 10;
        System.out.println(avg);</code></pre><h3 id="👉두번째-example-코드흐름">👉두번째 example 코드흐름</h3>
<ol>
<li><code>int sum = 0;</code> 이라는 전역변수 선언</li>
<li><code>for</code>가 읽혀 <code>int i=1</code> 라는 초기값을 가지고 <code>i&lt;11</code> 을 만족할 때까지 증가하는 <code>for문</code> 실행</li>
<li>전역변수를 끌어와 <code>sum = sum + i</code> 를 통해 기존의 값에 i를 더해가는 계산식을 실행 (<code>for</code> 내 존재하는 지역변수는 <code>for문</code>의 범위를 벗어나는 순간 폐기)</li>
<li>System.out.println(sum); 까지 실행 후 모든 코드를 실행시켰으니 다시 반복문으로 올라감. </li>
<li>점진적으로 증가하다 조건식에 만족하지 못했을 때 탈출하게 되며 이때 전역변수에 저장된 값을 불러와 10으로 나누면서 <code>avg</code> 라는 변수에 담아 평균 값을 계산한 후 출력.</li>
</ol>
<h3 id="--------------------------------------------------------------------------------1">-------------------------------------------------------------------------------</h3>
<h3 id="✏️공백을-포함하여-피라미드모양-별찍기">✏️공백을 포함하여 피라미드모양 별찍기.</h3>
<pre><code>// for문의 꽃 별찍기

        for(int i = 1; i&lt;6; i++){
            for(int j = 5; j&gt;i; j--){
                System.out.print(&quot; &quot;);
            }
            for(int n=0; n&lt;i; n++){
                System.out.print(&quot;*&quot;);
            }
            System.out.println();
        }</code></pre><h3 id="👉세번째-example-코드흐름">👉세번째 example 코드흐름</h3>
<ol>
<li>첫번째 <code>for문</code> 실행</li>
<li>두번째 <code>for문</code> 실행 -&gt; System.out.print(&quot; &quot;); <code>j&gt;i</code> (j&gt;1)가 만족할 때 까지 반복 -&gt; 탈출</li>
<li>세번째 <code>for문</code> 실행 -&gt; 동일하게 조건 만족할 때 까지 출력-&gt; 탈출</li>
<li>첫번째 <code>for문</code>에 해당하는  System.out.println(); 실행 후 다시 첫 번째 <code>for문</code> 타러 이동</li>
<li>i가 2를 가진 채로 2번과 3번 4번을 실행,i가 3를 가진 채로, i가 4를 가진 채 i가 5를 가진 채로 계속 반복하다 i가 6을 가지는 순간 <code>i&lt;6</code> 인 조건과 부합하지 않아 (flase) 첫 번째 <code>for문</code> 탈출. 첫 번째 for문을 탈출한 순간 두 번째 세 번째는 자연스럽게 타지못하게 됨. <img src="https://velog.velcdn.com/images/_error/post/631a8c74-2d45-4fa5-a0f1-50c1ba607c8c/image.png" alt=""></li>
</ol>
<p>  --작성중--</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 변수와 연산자]]></title>
            <link>https://velog.io/@_error/Java-%EB%B3%80%EC%88%98%EC%99%80-%EC%97%B0%EC%82%B0%EC%9E%90</link>
            <guid>https://velog.io/@_error/Java-%EB%B3%80%EC%88%98%EC%99%80-%EC%97%B0%EC%82%B0%EC%9E%90</guid>
            <pubDate>Wed, 14 Aug 2024 01:07:54 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/_error/post/430ab003-1676-4163-b399-77a27a2fddcd/image.png" alt=""></p>
<blockquote>
<h3 id="📂변수variable">📂변수(variable)</h3>
<p>  하나의 값을 저장할 수 있는 메모리 공간(RAM)
  어렵다면 &quot; <strong>물건을 담을 수 있는 상자</strong> &quot; 라고 생각해보자.</p>
</blockquote>
<p><em>🔎상황 1. 핸드폰을 팔기로 했다. 핸드폰을 구매자에게 배송해야하는데 배송하기 전 포장에 단계에서 어떤 상자를 고를지 골라야한다. 그렇다면 당신은 두손에 들어오는 크기의 핸드폰을 냉장고나 들어갈 법한 상자에 포장을 할 것인가?
적당한 크기의 상자에 담는 것이 정상이다.</em></p>
<p><em>🔎상황 2. 냉동 식품을 포장하고자한다. 장시간 이동을 해야하며 이때 선택할 수 있는 선택지 중 제일 좋은 것은 보냉이 되는 포장용기에 하는 것이 가장 좋은 선택일 것이다.</em></p>
<hr>
<p>이렇게 우리는 일상생활에서도 자연스럽게 적합한 용기 및 포장 방식을 택하고 물건을 담는다.</p>
<p><strong>Java에서 변수도 그렇다.</strong></p>
<p><strong>값을 저장하기 위해  저장하고자하는 값에 걸맞는 타입을 선택해야한다.</strong></p>
<p><img src="https://velog.velcdn.com/images/_error/post/b91263e4-99e2-4f4e-bb7c-928204870a6e/image.png" alt=""></p>
<p>내가 숫자 중 &quot;정수&quot;를 저장하고자 한다면 &quot;정수&quot;에 맞는 변수 타입을(상자)를 선택해야하며 저장하고자 하는 정수의 크기에 따라 상자의 크기를 선택하면 된다.
&quot;실수&quot;를 저장하고자 한다면 &quot;실수&quot;에 맞는 타입, 문자라면 문자에 맞는 타입을 선택하면 된다.</p>
<p><img src="https://velog.velcdn.com/images/_error/post/62139c4c-e912-4f1e-bd42-7f7271995d7c/image.png" alt=""></p>
<pre><code>int year = 2024;
System.out.println(&quot;올해:&quot; + year);
</code></pre><p>2024 라는 숫자를 담기위해 <strong><code>정수형 int 타입</code></strong> 을 선택하고 변수명을 &quot;<strong><code>year</code>
**&quot;이라 짓고 값을 넣어줬다.
그 후 출력하는 메소드를 통해 &quot;올해 : 2024&quot; 라는 결과를 출력할 수 있다.
분명 나는 올해 : year 이라고 작성했지만 **<code>year</code></strong>은 <strong><code>int year</code></strong> = 2024; 라는 초기화 과정을 통해 <strong><code>year</code></strong> 이라는 변수는 <strong><code>2024</code></strong>라는 값을 가지고있다. 
그래서 컴퓨터에서는 올해 : year을 올해 : 2024로 출력하는 것이다.</p>
<p>쉽게 이해하자면 이런 과정이지만 <span style='background-color: #fff5b1'> ** 더 좋은 개발자가 되기 위해선 이것보다 세부적으로 컴퓨터의 시점에서 이해를 해야한다. **<span></p>
<blockquote>
<p>  <strong>심화(처음이면 건너뛰기)</strong></p>
</blockquote>
<p>  <img src="https://velog.velcdn.com/images/_error/post/d1f06611-e0e0-4825-9424-683ecead8b7e/image.png" alt=""></p>
<ol>
<li>자바 소스코드(.java) 를 작성한다</li>
<li>자바 컴파일러가 자바 소스코드(.java)파일을 읽어 바이트코드(.class)코드로 컴파일 한다.</li>
<li>컴파일된 바이트코드(.class)를 JVM의 클래스로더(Class Loader)에게 전달한다.</li>
</ol>
<pre><code>JVM이란 자바 가상 머신 JVM(Java Virtual Machine)은 자바 프로그램 실행환경을 만들어 주는 소프트웨어</code></pre><p><img src="https://velog.velcdn.com/images/_error/post/e999a0a2-a6a1-4917-b03f-7335baf46a64/image.png" alt=""><span style="color:#808080">[출처 : <a href="https://blog.naver.com/chlwlstjd10/222239136195">https://blog.naver.com/chlwlstjd10/222239136195</a> ]</span></p>
<p>  클래스 로더는 .class 파일을 묶어서 JVM이 운영체제로부터 할당받은 메모리 영역인 Runtime Data Area로 적재한다.</p>
<p><strong>런타임 데이터 영역 (Runtime Data Area)
런타임 데이터 영역은 <code>JVM</code>의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역이다.</strong></p>
<p> 앞서 변수에 저장한 값은 <strong><code>런타임 데이터 영역</code></strong>에 저장되어 있다가 <strong><code>클래스 로더</code></strong>가 클래스 파일을 로드하는 과정에서 저장된 변수 값을 가져오게 된다.</p>
<p>  사용자 실행(run) -&gt; 컴파일러가 클래스 파일로 변환 -&gt; <strong><code>클래스 로더</code></strong>가 클래스 파일을 메모리에 로딩하고, <strong><code>JVM</code></strong>이 이를 실행한다 
 <strong><code>JVM</code></strong>에서 실행되어 그 안에 있는 시스템 호출이 이루어지면서 우리에게 보여지게 되는 것이다. </p>
<p>시스템호출 예시)  System.out.println()</p>
<blockquote>
<p>자료형 사용 예시   </p>
</blockquote>
<pre><code>byte age = 25;
short year = 2023;
int population = 1000000;
long universeAge = 13800000000L; // L을 붙여 long형임을 명시

float pi = 3.14f; // f를 붙여 float형임을 명시
double avogadro = 6.02214076e23;

char initial = &#39;A&#39;;

boolean isJavaFun = true;

</code></pre><h3 id="변수사용-예시">변수사용 예시</h3>
<pre><code>// 변수 선언
int num; // 정수형 변수 num 선언
double price = 19.99; // 실수형 변수 price 선언과 초기화

// 변수 값 할당
num = 10;
price = 29.99;

// 변수 사용
System.out.println(&quot;숫자: &quot; + num);
System.out.println(&quot;가격: $&quot; + price);

// 연산
int result = num + 10;
System.out.println(&quot;결과: &quot; + result);
</code></pre><p>  컴퓨터는 왼쪽에서부터 한 줄 한 줄 읽기 때문에</p>
<pre><code>  int box;
  System.out.println(&quot;변수는: &quot; + box);
  box = 100;

  **Error**
</code></pre><p>  왼쪽에서부터 읽어보자.</p>
<ol>
<li><strong><code>int</code></strong> 타입이라고 선언 후 변수 명을 <strong><code>box</code></strong>로 지었음 </li>
<li>컴퓨터는 <strong><code>int</code></strong>타입의 <strong><code>box</code></strong>라는 이름의 메모리를 할당 -&gt; 공간은 만들어둿지만 아직 값은 할당받지 못했음.</li>
<li>System.out.println 메소드를 통해 출력하고자하는데 &quot;변수는 :&quot; 여기까지는 문자열이니까 그냥 출력, 그 이후 <strong><code>box</code></strong>가 읽힘 </li>
<li><strong><code>box</code></strong>를 읽은 컴퓨터는 <strong><code>box</code></strong>라는 변수가 있나 찾아봄. 그러나 <strong><code>box</code></strong>라는 공간은 찾았으나 값이 없음. 컴퓨터는 가져오지못했고 이 과정에서 에러 발생. --여기서 종료 --</li>
</ol>
<ul>
<li><strong><code>box</code></strong> = 100; 이 3번 째 줄에 나왔으나 이미 2번째 줄에서 오류로 인해 진행하지 못했음. </li>
</ul>
<blockquote>
<h3 id="🖥연산자operator">🖥연산자(Operator)</h3>
<p>  <img src="https://velog.velcdn.com/images/_error/post/4d41a786-913c-4021-9088-e8a35b29de42/image.png" alt=""></p>
</blockquote>
<h3 id="연산자-사용예시">연산자 사용예시</h3>
<pre><code>    import java.util.Scanner;

    Scanner input = new Scanner(System.in);

    System.out.println(&quot;비교할 첫 번째 숫자를 입력하시오&quot;);
    int num1 = input.nextInt();

    System.out.println(&quot;비교할 첫 번째 숫자를 입력하시오&quot;);
    int num2 = input.nextInt();

    System.out.println(&quot;** 두 숫자를 비교하겠습니다 **&quot;);

    boolean result1 = num1 == num2;
    boolean result2 = num1 &gt; num2;
    boolean result3 = num1 &lt; num2;
    boolean result4 = num1 &gt;= num2;
    boolean result5 = num1 &lt;= num2;
    boolean result6 = num1 != num2;

    System.out.println(&quot;입력한 숫자가 같은지 확인하겠습니다. : &quot; + result1);
    System.out.println(&quot;첫 번째 입력한 숫자가 더 큰 숫자인지 확인하겠습니다.: &quot; + result2);
    System.out.println(&quot;첫 번째 입력한 숫자가 더 작은 숫자인지 확인하겠습니다.: &quot; + result3);
    System.out.println(&quot;첫 번째 입력한 숫자가 크거나 같은지 확인하겠습니다.: &quot; + result4);
    System.out.println(&quot;첫 번째 입력한 숫자가 작거나 같은지 확인하겠습니다.: &quot; + result5);
    System.out.println(&quot;입력한 두 숫자가 다른지 확인하겠습니다.: &quot; + result6);
</code></pre><p><strong><code>연산자</code></strong>를 이용하여 변수끼리 간단한 비교를 할 수 있으며 추후 <strong><code>조건문</code></strong>이나 <strong><code>반복문</code></strong> 등에서 굉장히 많이 사용된다.</p>
<p><strong>논리연산자 사용예시</strong></p>
<pre><code>// 논리연산자
    // or 연산자, 둘 중 하나라도 true 이면 true 반환.
    boolean ggg = 1 &gt; 2 || 2 == 2;
    System.out.println(ggg);

    // and 연산자, 둘 다 true여야 true를 반환
    boolean hhh = 1 &gt; 2 &amp;&amp; 2 == 2;
    System.out.println(hhh);

    // xor 연산자, 둘 중 하나만 true이여야 true를 반환.
    boolean iii = 1 &gt; 2 ^ 2 == 2;
    System.out.println(iii);
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Spring 개발은 Spring Boot을 알기 전과 후로 나뉜다. <Boot 셋팅하기>]]></title>
            <link>https://velog.io/@_error/Spring-%EA%B0%9C%EB%B0%9C%EC%9D%80-Spring-Boot%EC%9D%84-%EC%95%8C%EA%B8%B0-%EC%A0%84%EA%B3%BC-%ED%9B%84%EB%A1%9C-%EB%82%98%EB%89%9C%EB%8B%A4</link>
            <guid>https://velog.io/@_error/Spring-%EA%B0%9C%EB%B0%9C%EC%9D%80-Spring-Boot%EC%9D%84-%EC%95%8C%EA%B8%B0-%EC%A0%84%EA%B3%BC-%ED%9B%84%EB%A1%9C-%EB%82%98%EB%89%9C%EB%8B%A4</guid>
            <pubDate>Wed, 12 Jun 2024 16:36:51 GMT</pubDate>
            <description><![CDATA[<h1 id="intellij-로-span-stylecolor-008000spring-bootspan-셋팅하기">IntelliJ 로 <span style="color: #008000">Spring Boot</span> 셋팅하기.</h1>
<h2 id="1-spring-initializr-설정하기">1. Spring Initializr 설정하기</h2>
<h2 id="1-1-spring-initializr란">1-1. Spring Initializr란?</h2>
<ul>
<li>String initializr은 스프링부트를 기반으로 spring관련 프로젝트를 생성해주는 사이트로 프로젝트를 다운하여 쉽게 사용이 가능하도록 만든 사이트.</li>
<li>IDE에서 직접 New Project를 생성할수도 있지만 과정이 귀찮기 때문에 <span style='background-color:#fff5b1'> Spring Iinitializr을 사용했다.</span></li>
</ul>
<blockquote>
<p>🔎주소: <a href="https://start.spring.io/">https://start.spring.io/</a></p>
</blockquote>
<p>사이트에 접속하면 다음과 같은 화면이 나타난다.
<img src="https://velog.velcdn.com/images/_error/post/bf110dd8-baf6-4bc0-a0b2-c6c9b2d73401/image.png" alt=""></p>
<p><strong>Project</strong>
Gradle VS Maven</p>
<p>Gradle 이 더 성능이 좋으나 아직 많은 사람들이 전통적인 Maven에 익숙한 점 때문에 협업을 위해 Maven을 택하기도 함. 이번 포스팅은 Maven으로 셋팅.</p>
<blockquote>
<p>구조 설명</p>
</blockquote>
<ul>
<li>Project: SpringBoot를 빌드하고 배포하는 방식이다.</li>
<li>Language: 사용하고자하는 언어를 선택하면 된다. (일반적으로 Java가 사용됨)</li>
<li>SpringBoot: 버전을 선택해 준다. SNAPSHOT은 데모버전이고 높은 버전은 높은 자바버전을 필요로 하므로 SNAPSHOT이 없는 낮은 버전을 선택하는 것이 좋다.</li>
<li>Group: 기업 도메인명</li>
<li>Artifact: 빌드되어 나올 결과물</li>
<li>Name: 프로젝트명 (일반적으로 Artifact와 동일하게 사용함)</li>
<li>Description: 설명Package name: 패키지이름(Group과 Artifact를 설정하면 자동으로 만들어 준다.)</li>
<li>Packaging: 기본이 .jar이다. (spring framework와 model2는 .war를 사용한다.</li>
</ul>
<h2 id="2-dependencies-추가하기">2. Dependencies 추가하기</h2>
<p><img src="https://velog.velcdn.com/images/_error/post/179e7487-7c44-418c-9626-7d93428ecec0/image.png" alt=""></p>
<p> <span style='background-color:#dcffe4'><strong>SpringWeb (중요)</strong></span>
웹 서비스를 만드는 데 가장 중요한 모듈이다. 내장 톰캣 뿐 아니라 Spring MVC 패턴을 구현하는 데 필요한 기능이 대부분 들어있다. REST API서버를 만든다면 필수이다.
<span style='background-color:#dcffe4'><strong>Lombok (추천, 거의 필수)</strong></span>
Class에 getter, setter, toString, equals, constructor 등의 메소드들을 간단한 어노테이션(@)으로 지정해줄 수 있어 자바특유의 장황한 클래스를 줄여준다.
<span style='background-color:#dcffe4'><strong>Spring Data JPA ( 필수 )</strong></span>
JPA는 Java Persistence API라고 하는데 자바 ORM기술의 토대를 이루는 기술 명세이다. Spring에서 DB를 다루는 거의 표준 기술인 상황이다. Class Entity를 마치 DB처럼 사용할 수 있는 매우 유용한 도구이다. (학습량 또한 엄청나다.)
<span style='background-color:#dcffe4'><strong>MySQL Driver</strong></span>
MySql의 드라이버를 자동으로 연결해준다.
<span style='background-color:#dcffe4'><strong>Spring Configuration Processor</strong></span>
스프링 개발을 하면서 application.yml 또는 application.properties를 작성할 때 추천을 받고 싶을 때 이 기능을 사용하면 된다.
<span style='background-color:#dcffe4'><strong>Spring Boot DevTools (취향에 따라 사용)</strong></span>
DevTools는 스프링 어플리케이션을 띄웠을 때, 재시작하지 않고 코드의 변화를 반영시킬 때 사용한다. HTML 파일의 경우 LiveReload 기능을 제공하여 저장하면 그 변화가 페이지에 바로 나타나게 할 수도 있다. (참고  velog.io/@bread_dd/Spring-Boot-Devtools)
<span style='background-color:#dcffe4'><strong>Thymeleaf</strong></span>
View 템플릿인 Thymeleaf를 사용할 수 있도록 하는 모듈이다. Spring에서 많이 사용하는 JSP는 Spring Boot에서는 잘 사용하지 않는다.</p>
<p><img src="https://velog.velcdn.com/images/_error/post/4f779dc1-65a5-45d9-95b5-0f4d217d8709/image.png" alt="">
Add Dependencies 를 클릭하여 필요한 의존성을 추가.</p>
<h2 id="3-intellij-에서-open">3. IntelliJ 에서 Open</h2>
<p><img src="https://velog.velcdn.com/images/_error/post/2bba78de-874a-4d1d-ab8d-60ea52ebf354/image.png" alt=""></p>
<p>그럼 프로젝트 구조가 이렇게 생성되는 것을 볼 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/_error/post/3cb25f23-2c7c-4fbc-ad9a-62e3533ffa1e/image.png" alt=""></p>
<p>우측 상단에 Run을 실행시켜보면 콘솔을 통해 실행결과를 알 수 있다. 
여기서 의존성에 외부 DB 의존성을 주입했다면 application.properties 또는 application.yml 에 외부 DB에 대한 정보들을 입력해줘야한다.</p>
<p>예시 (&#39;application.properties&#39;)</p>
<pre><code>spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=myuser
spring.datasource.password=mypassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver</code></pre><p>예시 (&#39;application.yml&#39;)</p>
<pre><code>spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: myuser
    password: mypassword
    driver-class-name: com.mysql.cj.jdbc.Driver</code></pre><p><img src="https://velog.velcdn.com/images/_error/post/1443bcc2-9ed2-44d5-8f69-a62aed8eeb18/image.png" alt=""></p>
<h2 id="4-srcmainjava-폴더-내-testcontroller를-생성하여-hello-world">4. src/main/java 폴더 내 TestController를 생성하여 &quot;Hello, world!&quot;</h2>
<p>를 출력하는 코드를 작성하여 정상적으로 작동하는지 확인한다.</p>
<pre><code>package com.StudySpringBoot.jojal;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class TestController {

    @RequestMapping(&quot;/&quot;)
    @ResponseBody
    public String helloWorld() {
        return &quot;Hello, world!&quot;;
    }
}</code></pre><p>@Controller 어노테이션으로 Controller임을 명시하고
@RequestMapping(&quot;/&quot;) 어노테이션으로 기본 요청 ( / )을 받도록 함.
@ResponseBody 어노테이션을 사용하게 되면 ViewResolver 대신에 HttpMessageConverter가 동작하여 view를 반환하는 게 아닌 문자 내용을 직접 반환.</p>
<p>IntelliJ에서 Run -&gt; Web에서 <a href="http://localhost:8080/">http://localhost:8080/</a> 으로 접속하여 서버연결 확인!</p>
<p><img src="https://velog.velcdn.com/images/_error/post/e0e8ac22-b206-4926-8a48-b2173f22fe10/image.png" alt=""></p>
<p><span style="color:red">Run 버튼이 비활성화 되어있을 때 해결방법</span></p>
<p>Run -&gt; Edit Contfiguration 클릭</p>
<p><img src="https://velog.velcdn.com/images/_error/post/fe55794e-7996-4e01-9f95-711bc47f8224/image.png" alt=""></p>
<p>좌측 상단 +버튼 선택 후 서버 선택, Spring boot 내장 서버를 사용하기에 Application 선택.</p>
<p><img src="https://velog.velcdn.com/images/_error/post/b3304485-dd3a-4fa9-9696-4e08dfc2b768/image.png" alt=""></p>
<p>Name 설정과 Main Class 를 선택해주면 Run 버튼이 활성화 될 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[IntelliJ SpringMVC 셋팅 방법]]></title>
            <link>https://velog.io/@_error/IntelliJ-SpringMVC-%EC%85%8B%ED%8C%85-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@_error/IntelliJ-SpringMVC-%EC%85%8B%ED%8C%85-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Wed, 12 Jun 2024 07:52:07 GMT</pubDate>
            <description><![CDATA[<h1 id="intellij-에서-springmvc-개발-셋팅-순서">IntelliJ 에서 SpringMVC 개발 셋팅 순서.</h1>
<blockquote>
<p> <strong>1. Maven 프로젝트 생성하기
     2. pom.xml에 depency 설정으로 spring framework 추가하기
     3. web.xml 설정
     4. servlet-context.xml 설정 (intellij에서는 dispatcher-servlet.xml)
     5. root-context.xml 설정 (intellij에서는 applicationContext.xml)
     6. 서버 설정 (Tomcat)
     7. Controller 생성
     8. views 폴더 생성하여 jsp 파일 관리하기
     9. 서버 실행 및 url 매핑에 따른 dispatcher Servlet 정상 동작 여부 확인</strong></p>
</blockquote>
<p><strong><span style='background-color: #fff5b1'>1. Maven 프로젝트 생성하기</span></strong></p>
<p>Flie -&gt; New -&gt; Project 클릭 </p>
<p><img src="https://velog.velcdn.com/images/_error/post/8fc18351-4be0-44c8-89fe-2815b191ab7c/image.png" alt=""></p>
<p>Name : 저장할 폴더명
Location : 저장할 위치
JDK : 사용하는 JDK 추가 (현 프로젝트는 Java 1.8 사용)
<em>*원하는 JDK 가 없을 때 JDK 부분 클릭 시 Add JDK 버튼이 있는데 다운 받은 JDK 폴더를 선택 후 OK 버튼 누르면 된다.</em>
Archetype : org.apache.maven.archetypes:maven-archetype-webapp 해당 주소 붙여넣기
Advanced Settings : 프로젝트에 맞게 변경해서 사용
<br><br></p>
<p><strong><span style='background-color: #fff5b1'>2. pom.xml에 depency 설정으로 spring framework 추가하기</span></strong></p>
<p><img src="https://velog.velcdn.com/images/_error/post/2629fd7e-710b-4fd6-9d47-628df3c03696/image.png" alt=""></p>
<p>pom.xml 파일에 들어가서 코드 붙여넣기</p>
<pre><code>&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
  xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;&gt;
  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  &lt;groupId&gt;org.example&lt;/groupId&gt;
  &lt;artifactId&gt;spring_example&lt;/artifactId&gt;
  &lt;packaging&gt;war&lt;/packaging&gt;
  &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;
  &lt;name&gt;spring_example Maven Webapp&lt;/name&gt;
  &lt;url&gt;http://maven.apache.org&lt;/url&gt;

  &lt;dependencies&gt;

    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework&lt;/groupId&gt;
      &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt;
      &lt;version&gt;4.0.4.RELEASE&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
      &lt;groupId&gt;junit&lt;/groupId&gt;
      &lt;artifactId&gt;junit&lt;/artifactId&gt;
      &lt;version&gt;3.8.1&lt;/version&gt;
      &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;

  &lt;build&gt;
    &lt;plugins&gt;
      &lt;plugin&gt;
        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
        &lt;version&gt;3.10.1&lt;/version&gt;
        &lt;configuration&gt;
          &lt;source&gt;1.8&lt;/source&gt;
          &lt;target&gt;1.8&lt;/target&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;
    &lt;/plugins&gt;
  &lt;/build&gt;


&lt;/project&gt;</code></pre><br>
여기서 

<pre><code>&lt;version&gt;4.0.4.RELEASE&lt;/version&gt;</code></pre><p>Version 태그는 4.0.4 이 사용되었지만  4.0.4 버전은 굳이 따라하지 않아도 된다. 
본인이 원하는 버전을 선택할 것</p>
<p><br><br></p>
<p><strong><span style='background-color: #fff5b1'>3. web.xml 설정</span></strong></p>
<p><img src="https://velog.velcdn.com/images/_error/post/14f76fc0-abcb-46f5-bbdc-e3391834d9a8/image.png" alt=""></p>
<p>프로젝트 폴더 / src / main / webapp / WEB-INF 폴더에 web.xml 파일에 아래 코드를 붙여넣자.</p>
<pre><code>&lt;!DOCTYPE web-app PUBLIC
        &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot;
        &quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot; &gt;

&lt;web-app&gt;
  &lt;display-name&gt;Archetype Created Web Application&lt;/display-name&gt;
  &lt;context-param&gt;
    &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
    &lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;
  &lt;/context-param&gt;
  &lt;listener&gt;
    &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
  &lt;/listener&gt;
  &lt;servlet&gt;
    &lt;servlet-name&gt;dispatcher&lt;/servlet-name&gt;
    &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;dispatcher&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
&lt;/web-app&gt;</code></pre><br>

<p><strong><span style='background-color: #fff5b1'>4. servlet-context.xml 설정 (intellij에서는 dispatcher-servlet.xml)</span></strong>
<img src="https://velog.velcdn.com/images/_error/post/c3d54d1d-539d-4aca-a8ea-2789f3dd8adc/image.png" alt=""></p>
<p>src/main/webapp/WEB-INF 폴더 내에 dispatcher-servlet.xml 파일을 생성 후 코드 넣기.</p>
<p>*파일 생성 방법: WEB-INF 폴더 우클릭 후 New-&gt;File 을 선택 후  dispatcher-servlet.xml 이라고 짓기.</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
       xmlns:mvc=&quot;http://www.springframework.org/schema/mvc&quot;
       xsi:schemaLocation=&quot;http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd&quot;&gt;

    &lt;mvc:annotation-driven/&gt;
    &lt;context:component-scan base-package=&quot;controller&quot; /&gt;

    &lt;bean class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;&gt;
        &lt;property name=&quot;prefix&quot; value=&quot;/WEB-INF/views/&quot; /&gt;
        &lt;property name=&quot;suffix&quot; value=&quot;.jsp&quot; /&gt;
    &lt;/bean&gt;
&lt;/beans&gt;
</code></pre><br>

<p><strong><span style='background-color: #fff5b1'>5. root-context.xml 설정 (intellij에서는 applicationContext.xml)</span></strong></p>
<p><img src="https://velog.velcdn.com/images/_error/post/ef9eab1e-d5e4-4dbe-bc5a-35a3c99eab32/image.png" alt=""></p>
<p>src/main/webapp/WEB-INF 폴더 내에 applicationContext.xml 파일을 생성 후 코드 넣기.</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd&quot;&gt;

    &lt;!-- Root Context: defines shared resources visible to all other web components --&gt;

&lt;/beans&gt;</code></pre><br>

<p><strong><span style='background-color: #fff5b1'>6. 서버 설정 (Tomcat)</span></strong></p>
<p>shift 두번 누른후  All tap 에서 plugins 를 들어간다.
<img src="https://velog.velcdn.com/images/_error/post/1aed70b0-aba1-4978-a969-4138f39146d8/image.png" alt=""></p>
<p>Tomcat 을 검색하여 Smart Tomcat 을 install.
<img src="https://velog.velcdn.com/images/_error/post/82ef028d-793c-46f8-9ba5-6fe440ae1930/image.png" alt=""></p>
<p>톰캣 서버 다운로드, </p>
<p>원하는 위치에 압축을 풀고 IntelliJ에서 Run - Edit Configurations 선택
<img src="https://velog.velcdn.com/images/_error/post/6c19c219-16c4-4cc6-98e7-4fbf148d0e55/image.png" alt=""></p>
<p>좌측 상단에 + 버튼 클릭 후 Smart TomCat 추가.</p>
<p><img src="https://velog.velcdn.com/images/_error/post/2b90dd67-f0e0-4613-960d-ecd1b0a6c775/image.png" alt=""></p>
<p>Name : 알아서 짓기!  ( Tomcat {버전} 형식으로 지정했음 )</p>
<p>Tomcat Server : 아까 압축 푼 Tomcat 폴더 선택</p>
<p><strong><span style='background-color: #fff5b1'> <span style="color: red"> Context path: 기본 셋팅주소 (프로젝트 명으로 자동 셋팅 됨)
*기본 셋팅 요청 주소를 변경하고 싶으면 임의로 변경할 것  </span></span></strong></p>
<p>나머지도 다 자동 셋팅.</p>
<p><img src="https://velog.velcdn.com/images/_error/post/29bcfd9b-3427-470f-81a7-1441fc31d542/image.png" alt=""></p>
<p>서버 준비는 완료가 되었고 이제 웹 브라우저의 요청을 받기만 하면 됨.</p>
<br>

<p><strong><span style='background-color: #fff5b1'>7. Controller 생성</span></strong></p>
<p><img src="https://velog.velcdn.com/images/_error/post/c363b80a-068a-4dfc-9763-233d0863645d/image.png" alt=""></p>
<p>src/main 아래에 &quot;java&quot; 디렉토리 생성. 
<img src="https://velog.velcdn.com/images/_error/post/2f181425-e4f6-4ecf-b04f-3d859d9db58d/image.png" alt=""></p>
<p>java 디렉토리 즉, java 폴더 내에 controller  패키지 생성 -&gt; MainController 클래스 생성 후 코드 넣기 </p>
<pre><code>package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MainController {
    public MainController() {
    }

    @RequestMapping({&quot;/test&quot;})
    public String main() {
        return &quot;index&quot;;
    }
}
</code></pre><br>

<p><strong><span style='background-color: #fff5b1'>8. views 폴더 생성하여 jsp 파일 관리하기 </span></strong>
<img src="https://velog.velcdn.com/images/_error/post/53e81822-671c-45e9-91b3-27341cc5743d/image.png" alt=""></p>
<p>WEB-INF 폴더 내 views 폴더를 생성하여 index.jsp 를 옮기기.
모든 jsp 파일은 views 폴더 내에서 관리 </p>
<br>

<p><strong><span style='background-color: #fff5b1'>9. 서버 실행 및 url 매핑에 따른 dispatcher Servlet 정상 동작 여부 확인</span></strong></p>
<p><img src="https://velog.velcdn.com/images/_error/post/21d1c18f-2f4b-41e5-b17a-57c5d59760c4/image.png" alt=""></p>
<p>주소창에 localhost:8080/기본 Context Path 주소 / 요청주소 를 입력하면 정상적으로 출력됨!
기본 Context Path 주소를 모르겠다면 위에 꼼꼼히 다시 읽어보기.</p>
<pre><code>http://localhost:8080/SpringMVC/test </code></pre><p><span style='background-color: #ffdce0'>localhost:8080</span>
폼캣 포트 번호를 통한 서버 접근</p>
<p><span style='background-color: #ffdce0'>/SpringMVC</span>
tomcat 서버 설정할 때 기본 요청주소 즉, <span style="color: red">Context Path:</span> 에 적힌 요청 주소를 서버실행 시 무조건 실행.</p>
<p><span style='background-color: #ffdce0'>/test</span>
Web Brower에 요청 주소, Main Controller 에서 @RequestMapping 으로 /test 요청을 받아서 index로 return</p>
<pre><code> @RequestMapping({&quot;/test&quot;})
    public String main() {
        return &quot;index&quot;;
    }</code></pre><p>index 만 붙여도 dispatcher-servlet.xml 에서 설정된 셋팅으로 views 폴더 내 .jsp 파일을 찾아준다.</p>
<pre><code>&lt;bean class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;&gt;
        &lt;property name=&quot;prefix&quot; value=&quot;/WEB-INF/views/&quot; /&gt;
        &lt;property name=&quot;suffix&quot; value=&quot;.jsp&quot; /&gt;
    &lt;/bean&gt;</code></pre><p>그래서 index 만 요청하면 결국 /WEB-INF/views/index.jsp 을 자동으로 맵핑한다.</p>
<p>페이지가 404 Error 가 떠서 찾을 수 없을 경우 dispatcher-servlet.xml 에서 기본적으로 어느 루트를 요청하고 있는지, 그 요청한 루트에 return 하고자하는 .jsp 파일이 존재하는지 확인할 것.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring 로그인 기능 구현]]></title>
            <link>https://velog.io/@_error/Spring-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@_error/Spring-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Wed, 12 Jun 2024 01:14:28 GMT</pubDate>
            <description><![CDATA[<h1 id="로그인-기능-구현하기">로그인 기능 구현하기</h1>
<blockquote>
<p><strong>1. 컨트롤러에서 요청받아 처리하기</strong></p>
</blockquote>
<pre><code>@Controller
public class UserController {

    @PostMapping(&quot;/login&quot;)
    public String login(@RequestParam(&quot;user_id&quot;) String user_id, @RequestParam(&quot;user_pw&quot;) String user_pw, HttpSession session, Model model) {
        boolean success = userService.login(user_id, user_pw);
        if (success) {
            session.setAttribute(&quot;LoginUser&quot;, user_id);
            return &quot;redirect:/index&quot;;
        } else {
            model.addAttribute(&quot;LoginError&quot;, &quot;아이디 또는 비밀번호가 올바르지 않습니다.&quot;);
            return &quot;Log_in&quot;;
            }
        }
    }</code></pre><blockquote>
<p><strong>2. Service interfaceclass 에 메소드 선언</strong></p>
</blockquote>
<pre><code>public interface UserService {
  boolean login(String user_id, String user_pw);
  }</code></pre><blockquote>
<p><strong>3. ServiceImpl 에서 메소드 구현하기</strong></p>
</blockquote>
<pre><code>@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public boolean login(String user_id, String user_pw) {
        UserBean userBean = userMapper.findByUser_id(user_id);
        if (userBean != null &amp;&amp; userBean.getUser_pw().equals(user_pw)) {
            return true;
        }
        return false;
        }
     }

</code></pre><blockquote>
<p><strong>4. Mapper.java 에서 메소드 선언</strong></p>
</blockquote>
<pre><code>@Mapper
public interface UserMapper {
    UserBean findByUser_id(@Param(&quot;user_id&quot;) String user_id);
    }</code></pre><blockquote>
<p> <strong>5. Mapper.xml 에서 쿼리문 사용</strong></p>
</blockquote>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;

&lt;!DOCTYPE mapper
  PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
  &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;

&lt;mapper namespace=&quot;com.SharePlatformProject.mapper.UserMapper&quot;&gt;

    &lt;select id=&quot;findByUser_id&quot; parameterType=&quot;String&quot; resultType=&quot;com.SharePlatformProject.beans.UserBean&quot;&gt;
        SELECT *
        FROM user
        WHERE user_id = #{user_id}
    &lt;/select&gt;


&lt;/mapper&gt;
</code></pre><h2 id="loginjsp"><strong>login.jsp</strong></h2>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=EUC-KR&quot; pageEncoding=&quot;EUC-KR&quot;%&gt;
&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;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot;&gt;
  &lt;title&gt;로그인&lt;/title&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;${pageContext.request.contextPath}/resources/css/Log_in.css&quot;&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;login form&quot;&gt;
      &lt;header&gt;로그인&lt;/header&gt;
      &lt;form action=&quot;${pageContext.request.contextPath}/login&quot; method=&quot;post&quot;&gt;
        &lt;input type=&quot;text&quot; name=&quot;user_id&quot; placeholder=&quot;Enter your id&quot;&gt;
        &lt;input type=&quot;password&quot;  name=&quot;user_pw&quot; placeholder=&quot;Enter your password&quot;&gt;
        &lt;input type=&quot;submit&quot; class=&quot;button&quot; value=&quot;Login&quot;&gt;

    &lt;c:if test=&quot;${not empty LoginError}&quot;&gt;
     &lt;div style=&quot;color: red&quot;&gt;${LoginError}&lt;/div&gt;
    &lt;/c:if&gt;

      &lt;/form&gt;
      &lt;div class=&quot;signup&quot;&gt;
        &lt;span class=&quot;signup&quot;&gt;아직 회원이 아니신가요?
         &lt;a href=&quot;${pageContext.request.contextPath}/Join&quot;&gt;회원가입하기&lt;/a&gt;
        &lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><h3 id="작동-과정">작동 과정</h3>
<p>Web Browser 에서 ** /login 요청발생** --&gt; Controller 에서 정의된 <strong>@Mapping</strong> 으로  <strong>/login 에 대한 요청처리</strong> --&gt;  <span style='background-color:#fff5b1'><strong>@Autowired private UserService userService;</strong> 로 <strong>Service를 자동연결</strong></span> --&gt; Service를 구현하는 Impl 에서도 <span style='background-color:#fff5b1'><strong>@Autowired private UserMapper userMapper;</strong> <strong>Mapper를 자동연결</strong></span> 함으로 써 서로 유기적으로 연결되며 이는 Inversion of Control(IoC) 컨테이너의 한 형태인 Dependency Injection(DI) 패턴을 구현한 것.</p>
<h3 id="코드-뜯어보기">코드 뜯어보기</h3>
<h3 id="controller-code">Controller Code</h3>
<ol>
<li><p>@PostMapping(&quot;/login&quot;) 으로 /login에 대한 요청을 받는다.</p>
</li>
<li><p>public String login(<span style='background-color:#fff5b1'><strong>@RequestParam(&quot;user_id&quot;) String user_id</strong></span>, <span style='background-color:#fff5b1'><strong>@RequestParam(&quot;user_pw&quot;) String user_pw</strong></span>, <span style='background-color:    #dcffe4'>HttpSession session</span>, <span style='background-color:#f5f0ff'>Model model</span>) {
}</p>
<br>

</li>
</ol>
<p>(1) <span style='background-color:#fff5b1'> <strong>@RequestParam(&quot;user_id&quot;) String user_id</strong> </span> 와 <span style='background-color:#fff5b1'><strong>@RequestParam(&quot;user_pw&quot;) String user_pw</strong></span>
을 통해서 브라우저가 전송한 요청 중에서 user_id와 user_pw라는 이름의 파라미터를 각각 메소드 인자 <strong>user_id와</strong> <strong>user_pw로</strong> 받아오도록 지정. 
받은 걸로  boolean success = userService.login(<strong>user_id</strong>, <strong>user_pw</strong>); 에 전달하여 로그인 로직을 수행한다.</p>
<p><em>login.jsp 을 확인해보면 input 타입의 name 이 *</em>user_id, user_pw** 로 설정되어있는데 이것을 받아오는 것.
<br></p>
<p>(2) <span style='background-color:    #dcffe4'> <strong>HttpSession session</strong></span> 으로 <span style='background-color:    #dcffe4'><strong>HttpSession</strong></span>타입의 <span style='background-color:    #dcffe4'><strong>session</strong></span>객체를 생성하고 
     boolean success = userService.login(user_id, user_pw);
        if (success) {
            <span style='background-color:    #dcffe4'><strong>session</strong></span>.setAttribute(&quot;LoginUser&quot;, user_id);
            return &quot;redirect:/index&quot;;
        } </p>
<p>boolean 타입으로 결과가 true or flase 가 success에 반환되는데 success가 참이면 
<span style='background-color:    #dcffe4'><strong>session</strong></span>.setAttribute(&quot;LoginUser&quot;, user_id); 즉, user_id를 <span style='background-color:    #dcffe4'><strong>session</strong></span>에 setting 하게된다. 
<span style='background-color:    #dcffe4'><strong>*session</strong></span>은 브라우저가 종료되기전까지 메모리를 유지한다.
<br></p>
<p>(3) <span style='background-color:#f5f0ff'><strong>Model model</strong></span> , <span style='background-color:#f5f0ff'><strong>Model</strong></span> 타입의 <span style='background-color:#f5f0ff'><strong>model</strong></span> 이라는 객체를 생성하고</p>
<p> else {
           <span style='background-color:#f5f0ff'> <strong>model</strong></span>.addAttribute(&quot;LoginError&quot;, &quot;아이디 또는 비밀번호가 올바르지 않습니다.&quot;);
            return &quot;Log_in&quot;;
        }
        boolean 타입으로 결과 즉, success에 담긴 결과가 거짓일 시 
  <span style='background-color:#f5f0ff'> <strong>model</strong></span> 객체에 addAttribute(&quot;LoginError&quot;, &quot;아이디 또는 비밀번호가 올바르지 않습니다.&quot;);
&quot;LoginError&quot; 라는 이름으로 &quot;아이디 또는 비밀번호가 올바르지 않습니다.&quot; 값을 저장 후
View 에서 &quot;LoginError&quot; 에 접근하여 사용할 수 있다.</p>
<br>

<h3 id="service-code-serviceimpl-code">Service Code, ServiceImpl Code</h3>
<p>Service 에서 boolean타입의 login이라는 메소드를 선언하고 받을 파라미터 입력</p>
<pre><code>boolean login(String user_id, String user_pw);</code></pre><p>ServiceImpl 에서 Service에 선언된 메소드를 구현</p>
<pre><code> @Override
    public boolean login(String user_id, String user_pw) {
        UserBean userBean = userMapper.findByUser_id(user_id);
        if (userBean != null &amp;&amp; userBean.getUser_pw().equals(user_pw)) {
            return true;
        }
        return false;
    }
</code></pre><p>@Override 로 구현했음을 명시적으로 표현하고 <strong>UserBean</strong> 타입의 <strong>userBean</strong> 객체를 생성하고 <strong>userBean</strong>에는 <strong>userMapper.findByUser_id(user_id);</strong> 이 값을 넣는다.
if, 만약 <strong>findByUser_id(user_id)</strong> 이  <span style="color: #FF0000">null </span> 이 아니면서 <strong>userBean.getUser_pw().equals(user_pw)</strong>, 
<strong>user_pw</strong>가 <strong>getUser_pw()</strong> 와 일치하는 경우 true를 리턴하고 조건에 만족하지 못한다면 false를 반환한다. 
<br></p>
<h3 id="mapperjava-mapperxml">Mapper.java, Mapper.xml</h3>
<p>Mapper.java 에 xml과 연동할 메소드를 선언</p>
<pre><code> UserBean findByUser_id(@Param(&quot;user_id&quot;) String user_id);</code></pre><p>Mapper.xml 에 id가 findByUser_id 인 user_id를 조회하는 select문을 사용</p>
<pre><code>    &lt;select id=&quot;findByUser_id&quot; parameterType=&quot;String&quot; resultType=&quot;com.SharePlatformProject.beans.UserBean&quot;&gt;
        SELECT *
        FROM user
        WHERE user_id = #{user_id}
    &lt;/select&gt;
</code></pre><p><br><br><br><br><br></p>
<h3 id="본-과정은-mybatis-연결이-된-상태를-가정하여-진행되었음">본 과정은 MyBatis 연결이 된 상태를 가정하여 진행되었음.</h3>
<p><strong>아래 코드는 본 과정에서 사용된 UserBean 코드</strong></p>
<pre><code>package com.SharePlatformProject.beans;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

public class UserBean {

    @NotBlank(message = &quot;사용자 이름은 필수 입력 값입니다.&quot;)
    @Size(min = 2, max = 50, message = &quot;사용자 이름은 2자 이상 50자 이하이어야 합니다.&quot;)
    private String user_name;
    //
    @NotBlank(message = &quot;사용자 ID는 필수 입력 값입니다.&quot;)
    @Pattern(regexp = &quot;^[A-Za-z0-9_]{5,20}$&quot;, message = &quot;사용자 ID는 5-20자의 알파벳, 숫자, 밑줄(_)만 가능합니다.&quot;)    
    private String user_id;
    //
    @NotBlank(message = &quot;비밀번호는 필수 입력 값입니다.&quot;)
    @Size(min = 8, message = &quot;비밀번호는 최소 8자 이상이어야 합니다.&quot;)
    private String user_pw;
    //
    @NotBlank(message = &quot;비밀번호 확인은 필수 입력 값입니다.&quot;)
    private String user_pw2;
    //
    @Min(value = 18, message = &quot;최소 나이는 1살입니다.&quot;)
    @Max(value = 150, message = &quot;최대 나이는 120살입니다.&quot;)
    private int user_age;

    //   ---getter and setter---


    public String getUser_name() {
        return user_name;
    }
    public void setUser_name(String user_name) {
        this.user_name = user_name;
    }
    public String getUser_id() {
        return user_id;
    }
    public void setUser_id(String user_id) {
        this.user_id = user_id;
    }
    public String getUser_pw() {
        return user_pw;
    }
    public void setUser_pw(String user_pw) {
        this.user_pw = user_pw;
    }
    public String getUser_pw2() {
        return user_pw2;
    }
    public void setUser_pw2(String user_pw2) {
        this.user_pw2 = user_pw2;
    }
    public int getUser_age() {
        return user_age;
    }
    public void setUser_age(int user_age) {
        this.user_age = user_age;
    }

}
</code></pre><p>로그인 기능 구현 끝!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring 첫 걸음마 복습하기]]></title>
            <link>https://velog.io/@_error/Spring-%EC%B2%AB-%EA%B1%B8%EC%9D%8C%EB%A7%88-%EB%B3%B5%EC%8A%B5%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@_error/Spring-%EC%B2%AB-%EA%B1%B8%EC%9D%8C%EB%A7%88-%EB%B3%B5%EC%8A%B5%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 04 Jun 2024 09:11:01 GMT</pubDate>
            <description><![CDATA[<h1 id="💻-회원가입-구현-과정">💻 회원가입 구현 과정</h1>
<blockquote>
<h4 id="1--회원가입-html에서-form-태그를-사용하여-회원가입-구조를-만들어준다">1.  회원가입 html에서 form 태그를 사용하여 회원가입 구조를 만들어준다.</h4>
</blockquote>
<p><img src="https://velog.velcdn.com/images/_error/post/05f8d949-2d61-4bf7-93aa-093de1958f65/image.png" alt=""></p>
<blockquote>
<h4 id="2---form-태그의-method를-span-stylebackground-colorfff5b1post-방식으로-정의span">2.   form 태그의 method를 <span style='background-color:#fff5b1'>post 방식으로 정의.</span></h4>
<p><img src="https://velog.velcdn.com/images/_error/post/d09e938f-462b-43a4-8826-6f7fada39b48/image.png" alt=""></p>
</blockquote>
<p>form 으로 작성하고 form에 작성된 내용을 <span style='background-color:#fff5b1'><strong>post 메소드로 정의해주고</strong></span> (method=&quot;post&quot;)
<br>
<span style='background-color:#ffdce0'>잠깐,</span> post 방식이란?</p>
<pre><code>&lt;form&gt; 태그를 사용할 때 데이터를 서버로 전송하는 방법 중 하나</code></pre><h4 id="post-방식의-특징">POST 방식의 특징</h4>
<ol>
<li><p><span style='background-color:#ffdce0'><strong>데이터 보안</strong></span> : POST 방식은 데이터를 HTTP 메시지의 바디 부분에 포함시켜 전송하기 때문에 URL에 정보가 노출되지 않는다. 이는 보안상의 이점을 제공하고 데이터가 주소 표시줄에 표시되지 않기 때문에 비밀번호나 개인 정보 같은 민감한 데이터를 전송할 때 유용하다.</p>
</li>
<li><p><span style='background-color:#ffdce0'><strong>데이터 크기 제한 없음</strong></span> : POST 방식은 GET 방식과 달리 전송할 수 있는 데이터의 양에 대한 제한이 없다. 따라서 많은 양의 데이터를 전송해야 할 때 적합하다.</p>
</li>
<li><p><span style='background-color:#ffdce0'><strong>데이터 타입 제한 없음</strong></span> : POST 방식은 텍스트 데이터뿐만 아니라, 파일과 같은 바이너리 데이터도 전송할 수 있다.</p>
</li>
</ol>
<p>본론으로 돌아와서, 이걸 DB에 저장하기 위해 <span style='background-color:#fff5b1'><strong>저장소 역할로 먼저 VO 또는 Bean 클래스를 정의</strong> </span> 하고 필요한 타입과 변수명을 선언 한 뒤 Getter and Setter(Source-Generate-getter and setter) 작업을 해준다.</p>
<p><span style='background-color:#f6f8fa'><em>*Mybatis 설정은 제외하였음, 설정 및 Mapper 연동은 다음 포스팅에서 다룰 예정.</em> </span> </p>
<blockquote>
<h4 id="3controller-에서--postmapping으로-요청-받기">3.Controller 에서  @PostMapping으로 요청 받기.</h4>
</blockquote>
<pre><code>@PostMapping(&quot;/Join_Test&quot;)
public Stirng Join_Test(){
    //수행할 로직 작성
}</code></pre><p><img src="https://velog.velcdn.com/images/_error/post/3c49b1b0-1fae-435f-92d3-b4ac0fba81c5/image.png" alt=""></p>
<p>코드설명 :</p>
<blockquote>
<p>JSP에서 회원가입 버튼을 눌렀을 때 발생하는 Join_Test 호출을 PostMapping으로 받은 다음
매서드를 실행시키게 된다. 메서드가 실행되면서 ( )안에 있는 파라미터 값들을 주입받게 되는데
UserBean 타입을 joinUserBean으로 바인딩하고 userBean이라는 이름의 모델에 추가한다.
그 후 @Valid으로 joinUserBean 객체의 검증을 수행한다.
( joinUserBean객체의 타입인 UserBean 클래스에 선언된 어노테이션을 기반으로 검사수행 )
BindingResult 타입을 result객체로 설정하고 검증 실패에 대한 결과가 이 BindingResult 객체에 저장된다. Model model에서 Model 객체를 model로 설정하고 model.addAttribute를 통해 데이터를 View로 전달하는 기능을 한다. model.addAttribute(&quot;idError&quot;, &quot;이미 사용 중인 아이디입니다.&quot;) 를 통해 view에선 idError 이름으로 접근이 가능해진다.</p>
</blockquote>
<h4 id="modelattribute파라미터명-주요-기능">@ModelAttribute(&quot;파라미터명&quot;) 주요 기능</h4>
<p><span style='background-color:#ffdce0'><strong>요청 파라미터 바인딩</strong></span> : HTTP 요청에 포함된 파라미터들을 자바 객체에 자동으로 바인딩한다. 이 때 @ModelAttribute가 붙은 파라미터는 요청 파라미터의 이름과 객체의 필드 이름이 매핑되어 자동으로 해당 필드에 값을 설정한다.</p>
<p><span style='background-color:#ffdce0'><strong>모델 데이터 추가</strong></span> : 메소드가 호출될 때 @ModelAttribute 어노테이션으로 정의된 객체는 자동으로 모델에 추가된다. 이렇게 모델에 추가된 객체는 뷰에서 사용할 수 있게 되어, 폼 데이터의 입력, 검증 실패 시 재입력 등의 처리가 용이해진다.
<br>
즉, <strong>@ModelAttribute(&quot;<span style='background-color:#f1f8ff'>userBean</span>&quot;) <span style='background-color:    #f5f0ff'>UserBean</span> <span style='background-color:#dcffe4'>joinUserBean</strong></span>에서 <span style='background-color:    #f5f0ff'>UserBean</span>타입의 <span style='background-color:#dcffe4'>joinUserBean</span>이라는 객체가 <span style='background-color:#f1f8ff'>&quot;userBean&quot;</span>이라는 이름으로 저장된다.</p>
<p><img src="https://velog.velcdn.com/images/_error/post/1bca6a0d-049e-490f-b051-93c36cf14f24/image.png" alt="">
<em>*JSP에서 modelAttribute로 접근한 모습</em></p>
<blockquote>
<h4 id="4-view에서-userbean이라는-파라미터명을-받아서-userbean에-저장되어있는-userbean타입의-joinuserbean-객체를-사용한다">4. View에서 userBean이라는 파라미터명을 받아서 userBean에 저장되어있는 UserBean타입의 joinUserBean 객체를 사용한다.</h4>
</blockquote>
<p><img src="https://velog.velcdn.com/images/_error/post/d7305479-e92b-4887-8105-82da851b86df/image.png" alt=""></p>
<p>view는 구현하고자하는 코드에 따라 입력 폼, UserBean에 쓰인 객체에 따라 입력이 달라지니 참고 정도로만 사용하자. 이 프로젝트에서 사용된 Bean은 간단하게 이름, 아이디, 비밀번호, 비밀번호 확인 나이이다.</p>
<pre><code>    @NotBlank(message = &quot;사용자 이름은 필수 입력 값입니다.&quot;)
    @Size(min = 2, max = 50, message = &quot;사용자 이름은 2자 이상 50자 이하이어야 합니다.&quot;)
    private String user_name;
    //
    @NotBlank(message = &quot;사용자 ID는 필수 입력 값입니다.&quot;)
    @Pattern(regexp = &quot;^[A-Za-z0-9_]{5,20}$&quot;, message = &quot;사용자 ID는 5-20자의 알파벳, 숫자, 밑줄(_)만 가능합니다.&quot;)    
    private String user_id;
    //
    @NotBlank(message = &quot;비밀번호는 필수 입력 값입니다.&quot;)
    @Size(min = 8, message = &quot;비밀번호는 최소 8자 이상이어야 합니다.&quot;)
    private String user_pw;
    //
    @NotBlank(message = &quot;비밀번호 확인은 필수 입력 값입니다.&quot;)
    private String user_pw2;
    //
    @Min(value = 18, message = &quot;최소 나이는 1살입니다.&quot;)
    @Max(value = 150, message = &quot;최대 나이는 120살입니다.&quot;)
    private int user_age;

        //   ---getter and setter---</code></pre><br>
<br>

<h4 id="📌-mvc구조">📌 MVC구조</h4>
<p><img src="https://velog.velcdn.com/images/_error/post/074d3135-a710-431c-ab8b-f00600a6fad7/image.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>