<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://gilhanbit.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://gilhanbit.github.io/" rel="alternate" type="text/html" /><updated>2025-07-15T07:46:56+00:00</updated><id>https://gilhanbit.github.io/feed.xml</id><title type="html">daily coding</title><subtitle>비전공자의 개발자 도전기!</subtitle><author><name>gilhanbit</name><email>rlaqnwksp@gmail.com</email></author><entry><title type="html">[Project] 스프링 프레임워크를 이용한 웹개발 프로젝트</title><link href="https://gilhanbit.github.io/spring/setting/" rel="alternate" type="text/html" title="[Project] 스프링 프레임워크를 이용한 웹개발 프로젝트" /><published>2025-06-25T00:00:00+00:00</published><updated>2025-06-25T00:00:00+00:00</updated><id>https://gilhanbit.github.io/spring/spring-setting</id><content type="html" xml:base="https://gilhanbit.github.io/spring/setting/"><![CDATA[<h2 id="환경세팅-개인-저장용">환경세팅 (개인 저장용)</h2>

<h3 id="1-프로젝트-생성">1. 프로젝트 생성</h3>
<blockquote>
  <p>https://start.spring.io/ 
<img src="/assets/images/posts_img/spring/setting/springinitializr.png" alt="프로젝트생성" /></p>
</blockquote>

<h3 id="2-dependencies-선택">2. Dependencies 선택</h3>
<ul>
  <li>Spring Web</li>
  <li>Spring boot dev tools</li>
  <li>Thymeleaf</li>
  <li>MySQL Driver</li>
  <li>Mybatis Framework</li>
  <li>Spring Data JPA</li>
  <li>Lombok (추가로 플러그인 설치 필요 file-setting-plugin)
<img src="/assets/images/posts_img/spring/setting/lombok.png" alt="롬복플러그인" /></li>
</ul>

<h3 id="3-동작-확인-controller--html">3. 동작 확인 (controller / html)</h3>
<ul>
  <li>ProjectnameApplication 코드 입력 -&gt; @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) -&gt; DB 설정 잠시 생략</li>
</ul>

<h3 id="4-file-setting">4. file setting</h3>
<blockquote>
  <p>build.gradle / application.yml
<img src="/assets/images/posts_img/spring/setting/gradle.png" alt="파일세팅" /></p>
</blockquote>

<h3 id="5-기능-테스트">5. 기능 테스트</h3>
<ul>
  <li>@ResponseBody</li>
  <li>Thymeleaf</li>
  <li>Mybatis</li>
  <li>DB</li>
</ul>]]></content><author><name>gilhanbit</name><email>rlaqnwksp@gmail.com</email></author><category term="Spring" /><category term="spring" /><category term="web" /><category term="project" /><summary type="html"><![CDATA[개인용 환경설정]]></summary></entry><entry><title type="html">[Spring] Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression</title><link href="https://gilhanbit.github.io/spring/null_data/" rel="alternate" type="text/html" title="[Spring] Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression" /><published>2025-06-11T00:00:00+00:00</published><updated>2025-06-11T00:00:00+00:00</updated><id>https://gilhanbit.github.io/spring/spring-null_data</id><content type="html" xml:base="https://gilhanbit.github.io/spring/null_data/"><![CDATA[<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">th:each=</span><span class="s">"card : ${cardList}"</span> <span class="na">class=</span><span class="s">"card border rounded mt-3"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"p-2 d-flex justify-content-between"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"font-weight-bold"</span> <span class="na">th:text=</span><span class="s">"${card.user.name}"</span><span class="nt">&gt;&lt;/span&gt;</span>

    <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"more-btn"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"https://www.iconninja.com/files/860/824/939/more-icon.png"</span> <span class="na">width=</span><span class="s">"30"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<p>MVC 패턴으로 view에 타임리프 문법으로 데이터를 뿌리는데 자꾸 아래 런타임 에러가 발생.</p>

<p><strong>Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression</strong></p>

<p>‘오타가 있나?’ 생각해서 꼼꼼하게 전부 확인해봤지만 오타는 찾을 수 없었다.</p>

<p>그리고 에러 문구 하단에서 <strong>Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field ‘name’ cannot be found on null</strong> 문구를 확인하고 디버깅으로 확인했지만 값은 제대로 들어오고 있는 상태.</p>

<p>‘제대로 넘어오고 있는데 대체 왜 null이라고 하는 걸까?’ 약 2시간을 view부터 역추적해서 코드를 확인했다.</p>

<p>그러나 코드에서 별다른 에러는 확인할 수 없었는데…</p>

<p>원인은 DB에 있었다.</p>

<p>과거 테스트 중에 null로 들어간 데이터가 있었던 것.</p>

<p>null로 들어와 not null로 수정 후, 테스트 데이터를 삭제하지 않아 계속해서 런타임 에러가 발생하고 있었다.</p>]]></content><author><name>gilhanbit</name><email>rlaqnwksp@gmail.com</email></author><category term="Spring" /><category term="springEL" /><category term="error" /><summary type="html"><![CDATA[SpringEL Exception의 다양한 원인]]></summary></entry><entry><title type="html">[Java] @Autowired, @RequiredArgsConstructor 차이</title><link href="https://gilhanbit.github.io/java/autowired/" rel="alternate" type="text/html" title="[Java] @Autowired, @RequiredArgsConstructor 차이" /><published>2025-05-29T00:00:00+00:00</published><updated>2025-05-29T00:00:00+00:00</updated><id>https://gilhanbit.github.io/java/java-autowired</id><content type="html" xml:base="https://gilhanbit.github.io/java/autowired/"><![CDATA[<p>Spring에는 Bean DI를 지원하는 대표적인 어노테이션인 @Autowired와 @RequiredArgsConstructor가 있다.</p>

<p>그러나 많은 사람들이 @Autowired대신 @RequiredArgsConstructor를 권장하는데 그 이유는 무엇일까?</p>

<p>먼저, 둘의 차이부터 알아보자.</p>

<hr />

<h2 id="1-autowired">1. @Autowired</h2>

<blockquote>
  <p>@Autowired를 활용한 DI를 필드 주입이라고 한다.</p>
</blockquote>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MyService</span> <span class="o">{</span>

    <span class="nd">@Autowired</span>
    <span class="kd">private</span> <span class="nc">UserRepository</span> <span class="n">userRepository</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>이 Annotation을 특정 필드에 부여하면 Spring IoC Container 안에 존재하는 해당 Type의 Bean을 찾아 자동 주입해준다.</p>

<p>위 코드를 해석하자면 Spring IoC Container가 관리하고 있는 UserRepository 타입의 Bean이 userRepository 매개변수에 주입되는 것이다.</p>

<hr />

<h2 id="2-requiredargsconstructor">2. @RequiredArgsConstructor</h2>

<blockquote>
  <p>@RequiredArgsConstructor를 활용한 DI를 생성자 주입이라고 한다.</p>
</blockquote>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@RequiredArgsConstructor</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">MyService</span> <span class="o">{</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">UserRepository</span> <span class="n">userRepository</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>해당 Class의 생성자를 자동으로 만들어주는 lombok Annotation이다.</p>

<p>private final 접근제어자로 선언된 멤버변수를 생성자 파라미터로 넣어준다.</p>

<hr />

<h2 id="3-requiredargsconstructor를-권장하는-이유">3. @RequiredArgsConstructor를 권장하는 이유</h2>

<p>둘 다 똑같이 스프링 컨테이너가 관리하는 <strong>빈(bean)</strong>을 주입받기 위해 사용된다.</p>

<p>즉, 외부에서 객체를 생성하지 않고 스프링이 알아서 생성해 주입하도록 하는 방식이라는 건 같은데…</p>

<p>어째서 @RequiredArgsConstructor를 권장할까?</p>

<ol>
  <li>순환참조 에러 방지</li>
  <li>안정적 (final로 선언된 필드는 객체 생성 후 변경 불가)</li>
  <li>코드작성 용이 (매번 @Autowired를 쓸 필요 없음)</li>
</ol>

<ul>
  <li>순환참조란 A가 B를 필요로 하고, 동시에 B도 A를 필요로 하는 상황을 말한다.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">A</span> <span class="o">{</span>

  <span class="nd">@Autowired</span>
  <span class="kd">private</span> <span class="no">B</span> <span class="n">b</span><span class="o">;</span>
<span class="o">}</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">B</span> <span class="o">{</span>

  <span class="nd">@Autowired</span>
  <span class="kd">private</span> <span class="no">A</span> <span class="n">a</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>]]></content><author><name>gilhanbit</name><email>rlaqnwksp@gmail.com</email></author><category term="Java" /><category term="java" /><category term="autowired" /><category term="requiredargsconstructor" /><summary type="html"><![CDATA[@RequiredArgsConstructor를 권장하는 이유]]></summary></entry><entry><title type="html">[Java] 백엔드 Interview 1</title><link href="https://gilhanbit.github.io/java/ti1/" rel="alternate" type="text/html" title="[Java] 백엔드 Interview 1" /><published>2025-05-23T00:00:00+00:00</published><updated>2025-05-23T00:00:00+00:00</updated><id>https://gilhanbit.github.io/java/java-ti1</id><content type="html" xml:base="https://gilhanbit.github.io/java/ti1/"><![CDATA[<h2 id="객체지향-프로그래밍">객체지향 프로그래밍</h2>

<p>프로그램 구현에 필요한 객체를 파악, 역할을 정의하여 만들고 객체들간의 상호작용을 통해 프로그램을 만드는 것</p>

<h2 id="절차지향-프로그래밍">절차지향 프로그래밍</h2>

<p>프로그램의 순서와 흐름을 먼저 세우고 필요한 자료구조와 함수를 설계하는 방식</p>

<p>하나의 큰 기능을 위해 작은 기능들로 나누어 처리하는 top-down 방식이며, 여러 함수가 데이터를 공유한다.</p>

<p>유지보수가 어렵고 재사용성이 낮으며, 보안 개념이 약하다.</p>

<h2 id="객체지향--함수형-차이">객체지향 / 함수형 차이</h2>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>객체지향 프로그래밍 (OOP)</th>
      <th>함수형 프로그래밍 (FP)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>설계 방식</strong></td>
      <td><strong>객체 중심의 설계</strong></td>
      <td><strong>함수 중심의 설계</strong></td>
    </tr>
    <tr>
      <td><strong>코드 구조</strong></td>
      <td>객체들 간의 <strong>관계와 메시지 전달</strong> 중심</td>
      <td><strong>함수 조합과 데이터 흐름</strong> 중심</td>
    </tr>
    <tr>
      <td><strong>주요 단위</strong></td>
      <td>객체(클래스 기반)</td>
      <td>함수(값처럼 취급되는 연산 단위)</td>
    </tr>
    <tr>
      <td><strong>일급 객체</strong></td>
      <td>클래스 또는 객체</td>
      <td>함수 자체가 일급 객체</td>
    </tr>
    <tr>
      <td><strong>상태 변화</strong></td>
      <td>객체 내부 상태를 바꿀 수 있음</td>
      <td>상태 변화 지양, 불변성 추구</td>
    </tr>
    <tr>
      <td><strong>입력 → 출력</strong></td>
      <td>같은 입력이어도 <strong>상태에 따라 다른 결과</strong> 가능</td>
      <td>같은 입력이면 <strong>항상 같은 출력</strong> (순수 함수)</td>
    </tr>
  </tbody>
</table>

<h2 id="객체지향-프로그래밍의-장단점">객체지향 프로그래밍의 장단점</h2>

<p><strong>장점</strong></p>
<ul>
  <li>코드의 확장성과 재사용성이 좋다.</li>
  <li>유지보수가 용이하다.</li>
  <li>메서드로 접근하기 때문에 보안성이 좋다.</li>
</ul>

<p><strong>단점</strong></p>
<ul>
  <li>메모리 비용이 큼</li>
  <li>캡슐화, 격리구조로 인해 실행속도가 절차지향 프로그래밍에 비해 느림</li>
</ul>

<h2 id="객체지향-프로그래밍-4가지-특징">객체지향 프로그래밍 4가지 특징</h2>

<p><strong>추상화</strong>
필요한 정보만을 중심으로 구현</p>

<p><strong>캡슐화</strong>
객체가 독립적인 역할을 할 수 있도록 데이터와 기능을 묶어 관리한다.</p>

<p>실제 구현되는 부분을 외부에 드러나지 않도록 은닉화가 가능하다.</p>

<p><strong>상속성</strong>
다른 클래스의 기능을 물려받아 사용할 수 있다.</p>

<p>기존 코드를 재사용해 확장이 가능하다.</p>

<p><strong>다형성</strong>
하나의 클래스나 메서드가 다양한 방식으로 동작이 가능한 것을 말한다.</p>

<p>오버라이딩: 자식 클래스에서 부모 클래스의 기능을 재정의 하는 것
오버로딩: 메서드명은 동일하지만 파라미터 타입, 수를 다르게 하여 재사용하는 것</p>

<h2 id="객체지향-설계원칙-5가지-solid">객체지향 설계원칙 5가지 (SOLID)</h2>

<p><strong>단일 책임 원칙 (Single responsibility principle)</strong>
한 클래스는 하나의 책임만을 가진다.</p>

<p>클래스가 여러 기능을 갖게 될 경우 변경 사유가 많아지며, 변경할 경우 다른 기능에 영향을 끼친다.</p>

<p><strong>개방-폐쇄 원칙 (Open/closed principle)</strong>
소프트웨어 개체(클래스, 모듈, 함수 등)는 확장에 대해 열려있어야 하고, 변경에 대해서는 닫혀있어야 한다.</p>

<p>새로운 기능을 추가할 경우, 수정이 아니라 확장할 것</p>

<p><strong>리스코프 치환 원칙 (Liskov substitution principle)</strong>
자식 클래스가 부모 클래스를 대체할 수 있어야 한다.</p>

<p><strong>인터페이스 분리 원칙 (Interface segregation principle)</strong>
클라이언트가 사용하지 않는 메서드에 의존하지 않아야 한다.</p>

<p>큰덩어리의 인터페이스를 구체적이고 작은 단위로 분리해 꼭 필요한 메서드만 이용할 수 있게 한다.</p>

<p><strong>의존관계 역전 원칙 (Dependency inversion principle)</strong>
구체적인 구현이 아니라 추상화에 의존할 것</p>

<p>클래스간 의존성을 낮춰 유지보수를 편하게 하기 위함</p>

<h2 id="추상클래스와-인터페이스의-차이">추상클래스와 인터페이스의 차이</h2>

<table>
  <thead>
    <tr>
      <th>구분</th>
      <th><strong>추상 클래스</strong></th>
      <th><strong>인터페이스</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>목적</strong></td>
      <td>공통 기능 제공 (상속)</td>
      <td>규칙(계약) 정의 (구현 강제)</td>
    </tr>
    <tr>
      <td><strong>키워드</strong></td>
      <td><code class="language-plaintext highlighter-rouge">abstract class</code></td>
      <td><code class="language-plaintext highlighter-rouge">interface</code></td>
    </tr>
    <tr>
      <td><strong>상속/구현</strong></td>
      <td>단일 상속만 가능</td>
      <td>다중 구현 가능</td>
    </tr>
    <tr>
      <td><strong>메서드</strong></td>
      <td>추상 + 일반 메서드 둘 다 가능</td>
      <td>기본적으로 추상 메서드, Java 8 이후 <code class="language-plaintext highlighter-rouge">default</code>, <code class="language-plaintext highlighter-rouge">static</code> 메서드 허용</td>
    </tr>
    <tr>
      <td><strong>변수</strong></td>
      <td>일반 변수 선언 가능</td>
      <td><code class="language-plaintext highlighter-rouge">public static final</code> 상수만 선언 가능</td>
    </tr>
    <tr>
      <td><strong>생성자</strong></td>
      <td>있음 (생성자 호출 가능)</td>
      <td>없음</td>
    </tr>
    <tr>
      <td><strong>용도</strong></td>
      <td>유사한 객체들의 기본 기능 제공</td>
      <td>서로 다른 클래스 간 <strong>기능 통일</strong> 목적</td>
    </tr>
  </tbody>
</table>

<h2 id="jvm-실행-과정">JVM 실행 과정</h2>

<ol>
  <li>프로그램 실행</li>
  <li>OS로 부터 메모리 할당</li>
  <li>개발자 코드 작성</li>
  <li>javac가 바이트 코드 .class로 변환</li>
  <li>class loader가 jvm에 로딩</li>
  <li>execution engine을 통해 해석</li>
  <li>해석된 바이트코드가 runtime data area에 배치되어 실질적인 수행이 이루어짐</li>
</ol>

<h2 id="자바-메모리-구조">자바 메모리 구조</h2>

<p><strong>Method Area</strong></p>
<ul>
  <li>JVM이 실행되면서 생기는 공간이다.</li>
  <li>Class 정보, 전역변수 정보, Static 변수 정보가 저장되는 공간이다.</li>
  <li>Runtime Constant Pool 에는 말 그대로 ‘상수’ 정보가 저장되는 공간이다.</li>
  <li>모든 스레드에서 정보가 공유된다.</li>
</ul>

<p><strong>Heap</strong></p>
<ul>
  <li>new 연산자로 생성된 객체, Array와 같은 동적으로 생성된 데이터가 저장되는 공간</li>
  <li>Heap에 저장된 데이터는 Garbage Collector 가 처리하지 않는한 소멸되지 않는다.</li>
  <li>Reference Type 의 데이터가 저장되는 공간</li>
  <li>모든 스레드에서 정보가 공유된다.</li>
</ul>

<p><strong>Stack</strong></p>
<ul>
  <li>지역변수, 메소드의 매개변수와 같이 잠시 사용되고 필요가 없어지는 데이터가 저장되는 공간</li>
  <li>Last In First Out, 나중에 들어온 데이터가 먼저 나간다</li>
  <li>만약, 지역변수 이지만 Reference Type일 경우에는 Heap 에 저장된 데이터의 주소값을 Stack 에 저장해서 사용하게 된다.</li>
  <li>스레드마다 하나씩 존재한다.</li>
</ul>

<p><strong>PC Register</strong></p>
<ul>
  <li>스레드가 생성되면서 생기는 공간</li>
  <li>스레드가 어느 명령어를 처리하고 있는지 그 주소를 등록한다.</li>
  <li>JVM이 실행하고 있는 현재 위치를 저장하는 역할</li>
</ul>

<p><strong>Native Method Stack</strong></p>
<ul>
  <li>Java 가 아닌 다른 언어 (C, C++) 로 구성된 메소드를 실행이 필요할 때 사용되는 공간</li>
</ul>

<h2 id="가비지-컬렉션">가비지 컬렉션</h2>

<p>유효하지 않은 메모리인 가비지(Garbage)가 발생하는데 이를 알아서 정리해주는 것이 가비지 콜렉터이다.</p>

<h2 id="컬렉션-프레임워크">컬렉션 프레임워크</h2>

<p>배열을 사용하다 보면 여러가지 비효율적인 문제가 생긴다.</p>

<p>가장 큰 문제점은 크기가 고정적이라는 것이다.</p>

<p>배열의 크기는 생성할 때 결정되며 그 크기를 넘어가게 되면 더이상 데이터를 저장할 수 없다.</p>

<p>또 데이터를 삭제하면 해당 인덱스의 데이터는 비어있어 메모리가 낭비되는 등 여러 문제점들이 발생한다.</p>

<p>그렇기에 자바는 배열의 이러한 문제점을 해결하기 위해, <strong>널리 알려져 있는 자료구조를 바탕으로 객체나 데이터들을 효율적으로 관리(추가, 삭제, 검색, 저장)할 수 있는 자료구조들을 만들어 놓았다. 이러한 자료구조들이 있는 라이브러리를 컬렉션 프레임워크라고 한다.</strong></p>

<p>대표적으로는 List, Set, Map, Stack, Queue 등이 있다.</p>

<h2 id="servlet">Servlet</h2>

<p>자바 플랫폼에서 웹, 앱을 개발할 때 사용하는 기술.</p>

<p>코드 안에 HTML 태그가 삽입된다.</p>

<p>유지보수 측면에서 굉장히 비효율적이기 때문에 대부분 사용하지 않는다.</p>

<h2 id="jsp">JSP</h2>

<p>서블릿과 반대로 HTML 내에 자바 코드를 삽입해 개발하는 형식.</p>

<p>서블릿과 마찬가지로 비효율적이다.</p>

<h2 id="지역변수-정적변수와-전역변수">지역변수, 정적변수와 전역변수</h2>

<p><strong>지역변수</strong>
중괄호 {} 내에서만 작동하는 변수</p>

<p><strong>전역변수</strong>
클래스 내에 위치하기 때문에 전체 영역에서 사용이 가능한 변수이며 new로 초기화 시킬 수 있다.</p>

<p><strong>정적변수</strong>
static 프로그램 시작과 동시에 메모리에 올라간다.</p>

<p>프로그램 종료 전까지 메모리에 위치한다.</p>

<h2 id="접근제어자-종류">접근제어자 종류</h2>

<p><strong>public</strong>
public이 붙은 변수나 메서드는 <u>같은 프로젝트 안에서 사용 가능하다.</u></p>

<p><strong>default</strong>
접근 제어자가 아무것도 붙지 않은 변수나 메서드는 default 상태로, <u>같은 패키지 안에서만 사용 가능하다.</u></p>

<p><strong>protected</strong>
protected가 붙은 변수나 메서드는 다른 패키지에서는 사용이 불가능하다. 다만, 상속 관계일 때는 다른 클래스에서 사용 가능하다.</p>

<p><strong>private</strong>
private이 붙은 변수나 메서드는 같은 클래스 내에서만 사용 가능하다.</p>

<h2 id="접근-제어자를-사용하는-이유">접근 제어자를 사용하는 이유</h2>

<p>보안 때문이라고 할 수 있다.</p>

<p>만약에 웹사이트에서 아이디와 비밀번호 같은 중요한 정보를 public 변수에 저장을 한다면 아무데서나 직접적으로 접근하여 그 값을 변경할 수 있기 때문에 노출되기 쉽다.</p>

<p>이런 중요한 변수들은 대부분 private를 붙여준다.</p>

<p>또한, 여러 사람들과 함께 프로그램을 만들다 보면 다른 사람이 내가 만든 중요한 변수나 메서드를 무분별하게 사용하여 값을 변경할 수 있는데, 이를 막기 위해 상황에 맞는 접근 제어자를 사용한다.</p>

<h2 id="wrapper-class">Wrapper Class</h2>

<p><u>기본 자료타입(primitive type)을 객체로 다루기 위해서 사용하는 클래스</u>들을 래퍼 클래스(wrapper class)라고 한다.</p>

<p>자바는 모든 기본타입(primitive type)은 값을 갖는 객체를 생성할 수 있다.</p>

<p>이런 객체를 포장 객체라고도 하는데 그 이유는 기본 타입의 값을 내부에 두고 포장하기 때문이다.</p>

<p>래퍼 클래스로 감싸고 있는 기본 타입 값은 외부에서 변경할 수 없다.</p>

<p>만약 값을 변경하고 싶다면 새로운 포장 객체를 만들어야 한다.</p>

<h2 id="string--비교-시-true가-나오는-이유">String ‘==’ 비교 시 true가 나오는 이유</h2>

<p>== 연산자와 String 클래스의 equals() 메소드의 가장 큰 차이점은 == 연산자는 비교하고자 하는 두개의 대상의 주소값을 비교하고, String클래스의 equals() 메소드는 비교하고자 하는 두개의 대상의 값 자체를 비교한다.</p>

<p>String == 비교 시 true가 나오는 이유는, String Pool (상수 풀) 때문이다.</p>

<p>자바에서 “hello”처럼 쌍따옴표로 지정된 문자열 리터럴은 JVM이 Heap이 아닌 특별한 영역인 “String Constant Pool”에 저장해, <u>똑같은 문자열 리터럴이 두 번 나오면 JVM은 같은 주소를 공유하게 한다.</u></p>

<p>즉, a와 b는 같은 메모리 주소를 참조하게 되기 때문에 true를 반환한다.</p>

<hr />

<p><strong>참고</strong></p>

<ul>
  <li><a href="https://velog.io/@youngjun_10/BackEnd-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%A7%88%EB%AC%B8-%EC%A0%95%EB%A6%AC#%EC%A0%88%EC%B0%A8%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4%EB%9E%80">참고자료 1</a></li>
  <li><a href="https://velog.io/@tjddnths0223/%EB%A9%B4%EC%A0%91-Spring-%EB%B0%8F-%EB%B0%B1%EC%97%94%EB%93%9C-%EC%A7%88%EB%AC%B8%EB%A6%AC%EC%8A%A4%ED%8A%B8">참고자료 2</a></li>
  <li><a href="https://velog.io/@kkyes1210/CS-%EC%A0%95%EB%A6%AC-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%A7%88%EB%AC%B8-%EC%A0%95%EB%A6%AC-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B3%B5%ED%86%B5">참고자료 3</a></li>
  <li><a href="https://velog.io/@superscman/%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%A9%B4%EC%A0%91%EC%A4%80%EB%B9%84-4%ED%83%84">참고자료 4</a></li>
  <li><a href="https://velog.io/@tnscjs01/%EC%8B%A0%EC%9E%85-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%A7%88%EB%AC%B8-%EC%A0%95%EB%A6%AC-%EC%9E%90%EB%B0%94-%EC%9B%B9-%EA%B0%9C%EB%B0%9C">참고자료 5</a></li>
</ul>]]></content><author><name>gilhanbit</name><email>rlaqnwksp@gmail.com</email></author><category term="Java" /><category term="java" /><category term="기술면접" /><summary type="html"><![CDATA[Java, Spring, DB, CS]]></summary></entry><entry><title type="html">[CS] HTTP, HTTPS</title><link href="https://gilhanbit.github.io/cs/protocol/" rel="alternate" type="text/html" title="[CS] HTTP, HTTPS" /><published>2025-05-18T00:00:00+00:00</published><updated>2025-05-18T00:00:00+00:00</updated><id>https://gilhanbit.github.io/cs/cs-protocol</id><content type="html" xml:base="https://gilhanbit.github.io/cs/protocol/"><![CDATA[<p><strong>원글</strong></p>

<ul>
  <li><a href="https://velog.io/@reggias/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91HTTP-HTTPS">https://velog.io/@reggias</a></li>
</ul>

<hr />

<h2 id="1-http-https의-차이점">1. HTTP, HTTPS의 차이점</h2>

<p>HTTP는 인터넷상에서 정보를 주고 받는데 사용되는 프로토콜로 HTTP는 암호화되지 않은 텍스트 데이터를 전송하므로 보안이슈가 발생할 수 있다.</p>

<p>HTTPS의 S는 Secure로 HTTP와 HTTPS의 가장 큰 차이점이다.</p>

<p>SSL(Secure Sockets Layer) 업그레이드 버전인 TLS(Transport Layer Security) 인증서를 이용해 데이터를 암호화해 주고받는다.</p>

<hr />

<h2 id="2-https에-사용되는-ssltls">2. HTTPS에 사용되는 SSL/TLS</h2>

<p>브라우저(클라이언트)와 서버(웹사이트) 사이에 전송되는 데이터를 암호화하여 인터넷 연결을 보호하기 위한 표준 기술이다.</p>

<p>SSL이 먼저 개발되었으며 이를 업그레이드 한 것이 TLS다.</p>

<p>현재 SSL은 사용하지 않고 있으며, 편의상 SSL 인증서라고 부르지만 이는 TLS를 의미한다.</p>

<hr />

<h2 id="3-https의-동작-과정">3. HTTPS의 동작 과정</h2>

<ol>
  <li>브라우저가 서버 접속</li>
  <li>서버가 TLS 인증서를 브라우저에게 전송</li>
  <li>브라우저는 서버가 보내온 인증서를 검토 (발급기관, 만료일 등)</li>
  <li>브라우저가 TLS 연결을 위해 랜덤한 대칭키를 생성하며 이는 데이터 암호화 및 복호화에 사용됨</li>
  <li>브라우저가 서버에게 대칭키를 전달하기 위해 공개키 암호화 방식을 사용함</li>
  <li>서버가 자신의 개인키를 사용해 대칭키 복호화</li>
  <li>서로 대칭키를 사용해 데이터를 암호화하여 소통</li>
</ol>

<hr />

<h2 id="4-대칭키-개인키-암호화-방식">4. 대칭키, 개인키 암호화 방식</h2>

<p>HTTPS에서는 대칭키와 공개키 암호화 방식을 모두 사용한다.</p>

<p><strong><font color="#000099">대칭키 암호화 방식</font></strong>은 서버와 클라이언트가 암호화와 복호화에 같은 비밀키를 사용하는 방식으로 이는 데이터 전송 속도가 빠르고 간단한 암호화 방식이지만, 비밀키가 노출될 경우 보안성이 크게 떨어지게 된다.</p>

<p>따라서 HTTPS에서는 대칭키 암호화 방식을 사용하여 데이터를 암호화하고, 이 대칭키를 전달하는 과정에서 공개키 암호화 방식을 사용한다.</p>

<p><strong><font color="#000099">공개키 암호화 방식</font></strong>은 서버와 클라이언트가 각각 다른 비밀키를 가지고 있는 방식이다.</p>

<p>서버는 공개키를 클라이언트에게 제공하고, 클라이언트는 이 공개키를 이용하여 대칭키를 암호화하여 서버에 전달한다.</p>

<p>서버는 이 암호화된 대칭키를 자신의 개인키로 복호화하여 대칭키를 얻어내고, 이 대칭키를 사용하여 데이터를 암호화한다.</p>

<p>이 과정에서 중간에 도청자가 끼어들더라도, 공개키로 암호화된 대칭키를 해독할 수 없기 때문에 데이터의 기밀성이 보장된다.</p>

<p>또한, 서버 측의 개인키는 서버 외부에서 알 수 없도록 보안적으로 관리되기 때문에 데이터의 무결성과 인증성이 보장된다.</p>

<hr />

<h2 id="5-https-구현-방법">5. HTTPS 구현 방법</h2>

<ol>
  <li>SSL/TLS 인증서 발급
    <ol>
      <li>인증서는 인증기관(CA, Certificate Authority)에서 발급해주며, “서버의 도메인 이름, 공개키(Public Key), 발급자 정보, 유효 기간”과 같은 정보가 들어있다.</li>
    </ol>
  </li>
  <li>웹 서버 구성
    <ol>
      <li>웹 서버(Nginx, Apache, Spring 등)에 적용 해서 HTTPS를 사용할 수 있도록 설정해야 하며, 발급받은 TLS 인증서와 서버의 개인키를 등록한다.</li>
    </ol>
  </li>
  <li>클라이언트와의 통신 (TLS Handshake)
    <ol>
      <li>클라이언트는 서버와 연결을 시도할 때 SSL/TLS 핸드셰이크 과정을 거친다. 이 과정에서 서버는 발급받은 인증서를 클라이언트에게 제공하고, 클라이언트는 인증서의 정보를 확인한 후, 서버의 공개키를 사용하여 세션 키를 생성한다.</li>
    </ol>
  </li>
  <li>암호화 통신 (세션 키 사용)
    <ol>
      <li>브라우저와 서버는 위에서 만든 대칭키(세션 키)를 사용해 데이터를 암호화해서 주고받는다.</li>
    </ol>
  </li>
</ol>

<hr />

<h2 id="6-https를-사용하며-발생할-수-있는-성능-이슈와-개선방안">6. HTTPS를 사용하며 발생할 수 있는 성능 이슈와 개선방안</h2>

<p><strong><font color="#000099">암호화/복호화 작업:</font></strong> HTTPS는 암호화를 사용하여 통신을 보호한다. 암호화 및 복호화 작업은 CPU를 많이 사용하므로, 작업량이 많아질수록 서버의 성능에 영향을 줄 수 있다.</p>

<p>-&gt; HTTPS의 성능 이슈 중에서 가장 대표적인 것은 암호화/복호화 과정에서 발생하는 부하이다. 이러한 부하를 해결하기 위해 하드웨어 가속 기술을 사용할 수 있으며, 하드웨어 가속 기술은 SSL/TLS 암호화/복호화 과정을 CPU 대신 별도의 하드웨어 장치에서 처리함으로써 처리 속도를 향상시킨다.</p>

<p><strong><font color="#000099">핸드쉐이크 오버헤드:</font></strong> HTTPS 연결을 설정하는 과정에서 핸드쉐이크라는 절차를 거치게 됩니다. 이 과정에서 전송되는 데이터양이 많기 때문에, 핸드쉐이크 오버헤드가 발생할 수 있습니다.</p>

<p>-&gt; 암호화 알고리즘 최적화: HTTPS에서 사용되는 대표적인 암호화 알고리즘으로는 <code class="language-plaintext highlighter-rouge">AES</code>, <code class="language-plaintext highlighter-rouge">RSA</code>, <code class="language-plaintext highlighter-rouge">SHA</code> 등이 있다. 이러한 알고리즘들은 성능 향상을 위해 최적화될 수 있다. 예를 들어, RSA 알고리즘은 키의 크기에 따라 처리 속도가 크게 달라질 수 있기 때문에 키 크기를 최소화하는 것이 좋다.</p>

<p><strong><font color="#000099">캐시 불가능:</font></strong> HTTPS에서는 캐시가 불가능하다. 왜냐하면, 캐시된 데이터가 변조될 가능성이 있기 때문이다. 따라서, 매번 요청할 때마다 서버에서 새로운 데이터를 가져와야 하므로 성능에 영향을 줄 수 있다.</p>

<p>-&gt; 캐시: HTTPS의 경우 매번 인증서를 다운로드해야 하기 때문에 초기 연결 시간이 길어질 수 있다. 이를 해결하기 위해서는 캐시를 이용해야 한다. 캐시를 이용하면 인증서를 다운로드하지 않고 기존에 다운로드한 인증서를 사용함으로써 연결 시간을 단축시킬 수 있다.</p>

<p>-&gt; 세션 재사용: HTTPS는 기본적으로 연결마다 새로운 세션을 생성한다. 이러한 세션 생성 과정은 처리 시간이 오래 걸리므로, HTTPS에서는 기존에 생성된 세션을 재사용하는 방법을 이용해 성능을 개선할 수 있다.</p>

<p><strong><font color="#000099">CDN 사용 제약:</font></strong> HTTPS 연결을 설정할 때, 도메인 이름이 반드시 일치해야 한다. CDN을 사용하는 경우 도메인 이름이 변경되므로 HTTPS를 사용하기 어렵다. 이러한 경우에는 CDN에서 HTTPS를 지원하도록 설정해야 한다.</p>

<p>-&gt; CDN(Content Delivery Network): HTTPS에서 가장 큰 성능 이슈 중 하나는 지리적으로 떨어진 클라이언트와 서버 간의 지연 시간이다. 이를 해결하기 위해 CDN(Content Delivery Network)을 이용해야 한다. CDN은 전 세계에 분산된 캐시 서버를 이용하여 클라이언트와 가까운 서버에서 콘텐츠를 제공함으로써 지연 시간을 최소화 시킬 수 있다.</p>

<blockquote>
  <p>앞의 두 가지는 HTTPS의 성능 이슈를 해결하고 동시에 보안성 문제를 높이지 않는 방법이고, 뒤의 세 가지는 HTTPS에서 적용이 가능하나 보안성 문제와 관련된 취약점이 존재할 수 있어 충분한 보안 검사가 필요하다.</p>
</blockquote>

<hr />

<h2 id="7-서버측에서-주의해야-할-보안-이슈">7. 서버측에서 주의해야 할 보안 이슈</h2>

<ul>
  <li>
    <p><strong>인증서 유효성 검증:</strong> HTTPS를 사용하면 서버는 클라이언트에게 인증서를 제공하여 신뢰성을 보장한다. 따라서 서버 측에서는 인증서의 유효성을 검증하여 위조된 인증서를 사용한 공격을 방지해야 한다.</p>
  </li>
  <li>
    <p><strong>암호화 강도:</strong> HTTPS는 암호화된 통신을 제공하여 데이터의 안정성을 보장한다. 그러나 암호화 알고리즘의 강도에 따라 보안 수준이 달라질 수 있다. 서버 측에서는 보안 수준이 높은 암호화 알고리즘을 사용하여 공격에 대한 대비를 해야한다.</p>
  </li>
  <li>
    <p><strong>취약한 SSL/TLS 버전 사용:</strong> 오래된 SSL/TLS 버전은 보안 취약점이 존재하여 공격자가 중간자 공격을 수행할 수 있다. 따라서 서버 측에서는 최신 버전의 SSL/TLS 프로토콜을 사용하여 보안 취약점을 방지해야 한다.</p>
  </li>
  <li>
    <p><strong>HTTPS 트래픽 감시:</strong> HTTPS 통신은 암호화되어 있기 때문에 보안 검사나 감시가 어렵다. 하지만 일부 악성코드는 HTTPS 트래픽을 통해 악성코드를 전파하거나 민감한 정보를 수집하는 등의 공격을 하기 때문에, 서버 측에서는 HTTPS 트래픽을 감시하고 이상한 패턴을 탐지할 수 있는 시스템을 구축해야 한다.</p>
  </li>
</ul>

<hr />

<p><strong>참고</strong></p>

<ul>
  <li><a href="https://brunch.co.kr/@sangjinkang/38">참고자료 2</a></li>
  <li><a href="https://brunch.co.kr/@swimjiy/47">참고자료 3</a></li>
</ul>]]></content><author><name>gilhanbit</name><email>rlaqnwksp@gmail.com</email></author><category term="CS" /><category term="protocol" /><category term="http" /><category term="https" /><summary type="html"><![CDATA[HTTP, HTTPS 차이점]]></summary></entry><entry><title type="html">[Spring] 검사 기능 만들기</title><link href="https://gilhanbit.github.io/spring/duplicate/" rel="alternate" type="text/html" title="[Spring] 검사 기능 만들기" /><published>2025-05-13T00:00:00+00:00</published><updated>2025-05-13T00:00:00+00:00</updated><id>https://gilhanbit.github.io/spring/spring-duplicate</id><content type="html" xml:base="https://gilhanbit.github.io/spring/duplicate/"><![CDATA[<p>회원가입 시 아이디, 이메일 등 중복검사를 위한 기능을 구현하기 전에 이런 기능을 구현할 수 있는 AJAX에 대해 간단히 알아보자.</p>

<ul>
  <li><a href="https://jbground.tistory.com/4">참고</a></li>
</ul>

<p>AJAX는 ‘Asynchronous JavaScript And XML’의 약자로, 말 그대로 JavaScript와 XML 형식을 이용한 <strong>비동기적</strong> 정보 교환 기법이다.</p>

<p>js 코드로 서버에 요청 / 응답을 할 수 있다.</p>

<p>새로고침 시 전체 페이지를 새로 가져오는 것이 아니라, <strong>전체 페이지 중 일부만 가져오는 것이 가능</strong>하다.</p>

<p><img src="/assets/images/posts_img/spring/duplicate/asynchronous.png" alt="비동기의예" /></p>

<p>이미지 하단의 뉴스 더보기 버튼이 여기에 해당하며, 누르면 뉴스 영역만 서버에 요청한다.</p>

<p>과거에는 다른 방법으로 ajax를 사용했으나, jquery 점유율이 높아지며 주로 jquery를 이용해 실행한다.</p>

<p>그럼 회원가입 시 아이디, 이메일 등의 간단한 중복검사는 어떻게 하는지 코드를 통해 알아보자.</p>

<hr />

<h2 id="1-view">1. View</h2>

<p><img src="/assets/images/posts_img/spring/duplicate/duplicate.png" alt="연습문제" /></p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html</span> <span class="na">xmlns:th=</span><span class="s">"http://www.thymeleaf.org"</span> <span class="na">lang=</span><span class="s">"ko"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head&gt;</span>
    <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;title&gt;</span>bookmark<span class="nt">&lt;/title&gt;</span>
    <span class="c">&lt;!-- bootstrap --&gt;</span>
    <span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"</span> <span class="na">integrity=</span><span class="s">"sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://code.jquery.com/jquery-3.7.1.js"</span> <span class="na">integrity=</span><span class="s">"sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4="</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;&lt;/script&gt;</span>
    <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"</span> <span class="na">integrity=</span><span class="s">"sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct"</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"wrap"</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;h1&gt;</span>add bookmark<span class="nt">&lt;/h1&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;label&gt;</span>name<span class="nt">&lt;/label&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">id=</span><span class="s">"name"</span> <span class="na">class=</span><span class="s">"form-control"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;label&gt;</span>url<span class="nt">&lt;/label&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"d-flex"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">id=</span><span class="s">"url"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">placeholder=</span><span class="s">"http:// or https://"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">id=</span><span class="s">"checkBtn"</span> <span class="na">class=</span><span class="s">"btn btn-primary ml-3"</span> <span class="na">value=</span><span class="s">"중복확인"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;/div&gt;</span>
      <span class="nt">&lt;small</span> <span class="na">id=</span><span class="s">"statusArea"</span><span class="nt">&gt;&lt;/small&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">id=</span><span class="s">"addBtn"</span> <span class="na">class=</span><span class="s">"btn btn-success w-100"</span> <span class="na">value=</span><span class="s">"추가"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  
<span class="nt">&lt;script&gt;</span>
  <span class="nx">$</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
    <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#checkBtn</span><span class="dl">"</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">click</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
      <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#statusArea</span><span class="dl">"</span><span class="p">).</span><span class="nx">empty</span><span class="p">();</span>
      
      <span class="kd">let</span> <span class="nx">url</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#url</span><span class="dl">"</span><span class="p">).</span><span class="nx">val</span><span class="p">().</span><span class="nx">trim</span><span class="p">();</span>
      
      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">url</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#statusArea</span><span class="dl">"</span><span class="p">).</span><span class="nx">append</span><span class="p">(</span><span class="dl">'</span><span class="s1">&lt;span class="text-danger"&gt;url을 입력하세요.&lt;/span&gt;</span><span class="dl">'</span><span class="p">)</span>
      <span class="p">}</span>
      
      <span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">({</span>
        <span class="na">url</span><span class="p">:</span><span class="dl">"</span><span class="s2">/bookmark/duplicate</span><span class="dl">"</span>
        <span class="p">,</span> <span class="na">data</span><span class="p">:{</span><span class="dl">"</span><span class="s2">url</span><span class="dl">"</span><span class="p">:</span><span class="nx">url</span><span class="p">}</span>
        <span class="p">,</span><span class="na">success</span><span class="p">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">is_duplicate</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#statusArea</span><span class="dl">"</span><span class="p">).</span><span class="nx">append</span><span class="p">(</span><span class="dl">'</span><span class="s1">&lt;span class="text-danger"&gt;중복된 url입니다.&lt;/span&gt;</span><span class="dl">'</span><span class="p">)</span>
          <span class="p">}</span>
        <span class="p">}</span>
        <span class="p">,</span> <span class="na">error</span><span class="p">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
        <span class="p">}</span>
      <span class="p">});</span>
    <span class="p">});</span>
    
    <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#addBtn</span><span class="dl">"</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">click</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
      <span class="kd">let</span> <span class="nx">name</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#name</span><span class="dl">"</span><span class="p">).</span><span class="nx">val</span><span class="p">().</span><span class="nx">trim</span><span class="p">();</span>
      <span class="kd">let</span> <span class="nx">url</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#url</span><span class="dl">"</span><span class="p">).</span><span class="nx">val</span><span class="p">().</span><span class="nx">trim</span><span class="p">();</span>
      
      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">이름을 입력하세요.</span><span class="dl">"</span><span class="p">)</span>
        <span class="k">return</span><span class="p">;</span>
      <span class="p">}</span>
      
      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">url</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">주소를 입력하세요.</span><span class="dl">"</span><span class="p">)</span>
        <span class="k">return</span><span class="p">;</span>
      <span class="p">}</span>
      
      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="nx">url</span><span class="p">.</span><span class="nx">startsWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">http://</span><span class="dl">"</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">url</span><span class="p">.</span><span class="nx">startsWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">https://</span><span class="dl">"</span><span class="p">)))</span> <span class="p">{</span>
        <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">양식에 맞춰서 입력하세요.</span><span class="dl">"</span><span class="p">)</span>
        <span class="k">return</span><span class="p">;</span>
      <span class="p">}</span>
      
      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">url</span><span class="p">);</span>
      
      <span class="k">if</span> <span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#statusArea</span><span class="dl">"</span><span class="p">).</span><span class="nx">children</span><span class="p">().</span><span class="nx">length</span><span class="o">&lt;</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">({</span>
          <span class="na">type</span><span class="p">:</span><span class="dl">"</span><span class="s2">post</span><span class="dl">"</span>
          <span class="p">,</span><span class="na">url</span><span class="p">:</span><span class="dl">"</span><span class="s2">/bookmark/add</span><span class="dl">"</span>
          <span class="p">,</span><span class="na">data</span><span class="p">:{</span><span class="dl">"</span><span class="s2">name</span><span class="dl">"</span><span class="p">:</span><span class="nx">name</span><span class="p">,</span> <span class="dl">"</span><span class="s2">url</span><span class="dl">"</span><span class="p">:</span><span class="nx">url</span><span class="p">}</span>
          <span class="p">,</span><span class="na">success</span><span class="p">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">if</span> <span class="p">(</span><span class="nx">data</span> <span class="o">==</span> <span class="dl">"</span><span class="s2">success</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
                <span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="o">=</span><span class="dl">"</span><span class="s2">/bookmark/list</span><span class="dl">"</span>
              <span class="p">}</span>
          <span class="p">}</span>
          <span class="p">,</span><span class="na">error</span><span class="p">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">error</span><span class="p">,</span><span class="nx">xhr</span><span class="p">,</span><span class="nx">status</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">입력에 실패했습니다.</span><span class="dl">"</span><span class="p">)</span>
          <span class="p">}</span>
        <span class="p">});</span>
      <span class="p">}</span>
    <span class="p">});</span>
  <span class="p">});</span>
<span class="nt">&lt;/script&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<p>비어있거나 중복확인 버튼을 눌러 중복일 경우 출력되는 메시지가 없을 경우 저장하도록 <code class="language-plaintext highlighter-rouge">if ($("#statusArea").children().length&lt;1)</code> 조건문을 추가하였다.</p>

<p>그러나 문제는 중복확인을 한 번도 하지 않을 경우(이 또한 문구가 뜨지 않으므로)에도 저장이 된다는 것이었다.</p>

<p>(처음에는 $.ajax 안에 코드를 넣고 ‘이게 왜 되는 거지?’ 했던…. success 내부에 들어가는 것과 관계없이 ajax로 들어가는 순간 저장. success는 그냥 <strong>성공 시 출력을 담당</strong>한다 라고 생각하면 될듯함)</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">$</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
  <span class="kd">let</span> <span class="nx">isChecked</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
  
  <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#checkBtn</span><span class="dl">"</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">click</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
    <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#statusArea</span><span class="dl">"</span><span class="p">).</span><span class="nx">empty</span><span class="p">();</span>
    
    <span class="kd">let</span> <span class="nx">url</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#url</span><span class="dl">"</span><span class="p">).</span><span class="nx">val</span><span class="p">().</span><span class="nx">trim</span><span class="p">();</span>
    
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">url</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#statusArea</span><span class="dl">"</span><span class="p">).</span><span class="nx">append</span><span class="p">(</span><span class="dl">'</span><span class="s1">&lt;span class="text-danger"&gt;url을 입력하세요.&lt;/span&gt;</span><span class="dl">'</span><span class="p">)</span>
    <span class="p">}</span>
    
    <span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">({</span>
      <span class="na">url</span><span class="p">:</span><span class="dl">"</span><span class="s2">/lesson06/bookmark-duplicate</span><span class="dl">"</span>
      <span class="p">,</span> <span class="na">data</span><span class="p">:{</span><span class="dl">"</span><span class="s2">url</span><span class="dl">"</span><span class="p">:</span><span class="nx">url</span><span class="p">}</span>
      <span class="p">,</span> <span class="na">success</span><span class="p">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">is_duplicate</span><span class="p">)</span> <span class="p">{</span>
          <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#statusArea</span><span class="dl">"</span><span class="p">).</span><span class="nx">append</span><span class="p">(</span><span class="dl">'</span><span class="s1">&lt;span class="text-danger"&gt;중복된 url입니다.&lt;/span&gt;</span><span class="dl">'</span><span class="p">)</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
          <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#statusArea</span><span class="dl">"</span><span class="p">).</span><span class="nx">append</span><span class="p">(</span><span class="dl">'</span><span class="s1">&lt;span class="text-success"&gt;사용가능한 url입니다.&lt;/span&gt;</span><span class="dl">'</span><span class="p">)</span>
          <span class="nx">isChecked</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
        <span class="p">}</span>
      <span class="p">}</span>
      <span class="p">,</span> <span class="na">error</span><span class="p">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">false</span><span class="dl">"</span><span class="p">)</span>
      <span class="p">}</span>
    <span class="p">});</span>
  <span class="p">});</span>
  
  <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#addBtn</span><span class="dl">"</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">click</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nx">name</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#name</span><span class="dl">"</span><span class="p">).</span><span class="nx">val</span><span class="p">().</span><span class="nx">trim</span><span class="p">();</span>
    <span class="kd">let</span> <span class="nx">url</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#url</span><span class="dl">"</span><span class="p">).</span><span class="nx">val</span><span class="p">().</span><span class="nx">trim</span><span class="p">();</span>
    
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">이름을 입력하세요.</span><span class="dl">"</span><span class="p">)</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">url</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">주소를 입력하세요.</span><span class="dl">"</span><span class="p">)</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">url</span><span class="p">.</span><span class="nx">startsWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">http://</span><span class="dl">"</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">url</span><span class="p">.</span><span class="nx">startsWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">https://</span><span class="dl">"</span><span class="p">))</span> <span class="p">{</span>
      <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">양식에 맞춰서 입력하세요.</span><span class="dl">"</span><span class="p">)</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">url</span><span class="p">);</span>
    
    <span class="k">if</span> <span class="p">(</span><span class="nx">isChecked</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">({</span>
        <span class="na">type</span><span class="p">:</span><span class="dl">"</span><span class="s2">post</span><span class="dl">"</span>
        <span class="p">,</span><span class="na">url</span><span class="p">:</span><span class="dl">"</span><span class="s2">/lesson06/bookmark-add</span><span class="dl">"</span>
        <span class="p">,</span><span class="na">data</span><span class="p">:{</span><span class="dl">"</span><span class="s2">name</span><span class="dl">"</span><span class="p">:</span><span class="nx">name</span><span class="p">,</span> <span class="dl">"</span><span class="s2">url</span><span class="dl">"</span><span class="p">:</span><span class="nx">url</span><span class="p">}</span>
        <span class="p">,</span><span class="na">success</span><span class="p">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">if</span> <span class="p">(</span><span class="nx">data</span> <span class="o">==</span> <span class="dl">"</span><span class="s2">success</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="o">=</span><span class="dl">"</span><span class="s2">/lesson06/bookmark-list</span><span class="dl">"</span>
          <span class="p">}</span> 
          
        <span class="p">}</span>
        <span class="p">,</span><span class="na">error</span><span class="p">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">error</span><span class="p">,</span><span class="nx">xhr</span><span class="p">,</span><span class="nx">status</span><span class="p">)</span> <span class="p">{</span>
          <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">입력에 실패했습니다.</span><span class="dl">"</span><span class="p">)</span>
        <span class="p">}</span>
      <span class="p">})</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">중복확인이 필요합니다.</span><span class="dl">"</span><span class="p">)</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">});</span>
<span class="p">});</span>
</code></pre></div></div>

<p>그래서 <code class="language-plaintext highlighter-rouge">isChecked</code>라는 flag 변수를 사용했다. (현업에서도 이렇게 사용하는지는 모름….)</p>

<hr />

<h2 id="2-ajax에서-자주-사용하는-설정값">2. AJAX에서 자주 사용하는 설정값</h2>

<blockquote>
  <p>ajax를 사용하기 위해서는 필수로 알아야 할 설정값들이 있다.</p>
</blockquote>

<table>
  <thead>
    <tr>
      <th><strong>구분</strong></th>
      <th><strong>정의</strong></th>
      <th><strong>값</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>url</strong></td>
      <td>ajax 요청을 보낼 URL</td>
      <td>-</td>
    </tr>
    <tr>
      <td><strong>type</strong></td>
      <td>HTTP 요청 방식 (기본값:get`)</td>
      <td>get, post, delete, put</td>
    </tr>
    <tr>
      <td><strong>dataType</strong></td>
      <td>서버로부터 응답받을 데이터 타입. 생략 시 jQuery가 MIME 타입을 보고 자동 결정</td>
      <td>xml, html, json, script, jsonp, text</td>
    </tr>
    <tr>
      <td><strong>contentType</strong></td>
      <td>전송 시 데이터의 콘텐츠 타입 지정 (기본값: <code class="language-plaintext highlighter-rouge">application/x-www-form-urlencoded; charset=UTF-8</code>)</td>
      <td>application/json 등</td>
    </tr>
    <tr>
      <td><strong>timeout</strong></td>
      <td>요청 제한 시간 (ms 단위). 초과 시 실패 처리됨</td>
      <td>숫자 (ex: 3000)</td>
    </tr>
    <tr>
      <td><strong>data</strong></td>
      <td>서버로 전송할 데이터. <code class="language-plaintext highlighter-rouge">Object</code>, <code class="language-plaintext highlighter-rouge">String</code>, <code class="language-plaintext highlighter-rouge">Array</code> 등 사용 가능. <code class="language-plaintext highlighter-rouge">Object</code>일 경우 key-value 구조를 따르며, 값이 배열이면 자동 직렬화됨</td>
      <td>{name: “홍길동”, age: 20} 등</td>
    </tr>
    <tr>
      <td><strong>beforeSend</strong></td>
      <td>요청이 전송되기 전에 실행되는 콜백 함수. <code class="language-plaintext highlighter-rouge">false</code>를 반환하거나 <code class="language-plaintext highlighter-rouge">jqXHR.abort()</code>를 호출하면 요청이 취소됨</td>
      <td>function(xhr) { … }</td>
    </tr>
    <tr>
      <td><strong>success</strong></td>
      <td>통신이 성공했을 때 실행되는 콜백 함수</td>
      <td>function(response) { … }</td>
    </tr>
    <tr>
      <td><strong>error</strong></td>
      <td>통신이 실패했을 때 실행되는 콜백 함수 (단, <code class="language-plaintext highlighter-rouge">jsonp</code> 또는 <code class="language-plaintext highlighter-rouge">cross-domain</code> 요청은 해당 안 될 수 있음)</td>
      <td>function(xhr, status, error) { … }</td>
    </tr>
    <tr>
      <td><strong>complete</strong></td>
      <td><code class="language-plaintext highlighter-rouge">success</code> 또는 <code class="language-plaintext highlighter-rouge">error</code> 후 항상 호출되는 콜백 함수</td>
      <td>function(xhr, status) { … }</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="3-controller">3. Controller</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@RequestMapping</span><span class="o">(</span><span class="s">"/bookmark"</span><span class="o">)</span>
<span class="nd">@Controller</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Controller</span> <span class="o">{</span>

  <span class="nd">@Autowired</span>
  <span class="kd">private</span> <span class="nc">BookmarkBO</span> <span class="n">bookmarkBO</span><span class="o">;</span>
  
  <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/view"</span><span class="o">)</span>
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">view</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="s">"addBookmark"</span><span class="o">;</span>
  <span class="o">}</span>
  
  <span class="nd">@PostMapping</span><span class="o">(</span><span class="s">"/add"</span><span class="o">)</span>
  <span class="nd">@ResponseBody</span>
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">add</span><span class="o">(</span>
      <span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"name"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">name</span><span class="o">,</span>
      <span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"url"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">url</span><span class="o">)</span> <span class="o">{</span>
    
    <span class="n">bookmarkBO</span><span class="o">.</span><span class="na">setBookmark</span><span class="o">(</span><span class="n">name</span><span class="o">,</span><span class="n">url</span><span class="o">);</span>
    
    <span class="k">return</span> <span class="s">"success"</span><span class="o">;</span>
  <span class="o">}</span>
  
  <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/list"</span><span class="o">)</span>
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">list</span><span class="o">(</span><span class="nc">Model</span> <span class="n">model</span><span class="o">)</span> <span class="o">{</span>
    
    <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Bookmark</span><span class="o">&gt;</span> <span class="n">bookmark</span> <span class="o">=</span> <span class="n">bookmarkBO</span><span class="o">.</span><span class="na">getBookmark</span><span class="o">();</span>
    
    <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"bookmark"</span><span class="o">,</span> <span class="n">bookmark</span><span class="o">);</span>
    
    <span class="k">return</span> <span class="s">"bookmarkList"</span><span class="o">;</span>
  <span class="o">}</span>
  
  <span class="nd">@ResponseBody</span>
  <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/duplicate"</span><span class="o">)</span>
  <span class="kd">public</span> <span class="nc">Map</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Object</span><span class="o">&gt;</span> <span class="nf">isDuplicate</span><span class="o">(</span>
      <span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"url"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">url</span><span class="o">)</span> <span class="o">{</span>
    
    <span class="kt">boolean</span> <span class="n">isDuplicate</span> <span class="o">=</span> <span class="n">bookmarkBO</span><span class="o">.</span><span class="na">isDuplicate</span><span class="o">(</span><span class="n">url</span><span class="o">);</span>
        
    <span class="nc">Map</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Object</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">&lt;&gt;();</span>
    <span class="n">result</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"is_duplicate"</span><span class="o">,</span> <span class="n">isDuplicate</span><span class="o">);</span>
    
    <span class="k">return</span> <span class="n">result</span><span class="o">;</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>]]></content><author><name>gilhanbit</name><email>rlaqnwksp@gmail.com</email></author><category term="Spring" /><category term="spring" /><category term="ajax" /><summary type="html"><![CDATA[AJAX로 중복검사 하기]]></summary></entry><entry><title type="html">[Spring] redirect를 하는 이유</title><link href="https://gilhanbit.github.io/spring/redirect/" rel="alternate" type="text/html" title="[Spring] redirect를 하는 이유" /><published>2025-05-10T00:00:00+00:00</published><updated>2025-05-10T00:00:00+00:00</updated><id>https://gilhanbit.github.io/spring/spring-redirect</id><content type="html" xml:base="https://gilhanbit.github.io/spring/redirect/"><![CDATA[<p>request에 대한 response로 <code class="language-plaintext highlighter-rouge">redirect</code>, <code class="language-plaintext highlighter-rouge">foward</code>를 주로 사용한다.</p>

<p>그 이유는 무엇일까?</p>

<p>일단 redirect를 하는 이유를 말하기 전에 foward와의 차이를 알아보자.</p>

<hr />

<h2 id="1-redirect--foward-차이">1. redirect / foward 차이</h2>

<h3 id="1-1-redirect를-사용하는-경우">1-1. redirect를 사용하는 경우</h3>

<ol>
  <li>새로운 요청으로 전환해야 할 때</li>
  <li>URL 주소 변경이 필요할 때</li>
  <li>회원가입, 글쓰기 등의 시스템에 변화가 생길 때</li>
</ol>

<h3 id="1-2-foward를-사용하는-경우">1-2. foward를 사용하는 경우</h3>

<ol>
  <li>객체를 재사용 해야할 경우</li>
  <li>시스템에 변화가 생기지 않는 단순 조회 등의 경우</li>
</ol>

<hr />

<h2 id="2-왜-redirect를-사용할까">2. 왜 redirect를 사용할까?</h2>

<p>사이트에 회원가입이나, 결제, 게시판에 글을 쓸 경우 완료 페이지, 글목록으로 가는 경우가 이에 해당한다.</p>

<p>리다이렉트는 주로 <strong><font color="#990000">안전 / 안정성을 위해 사용한다고 생각하는데, 요청이 정상적으로 이루어졌음에도 다시 요청하는 것을 방지</font></strong>한다.</p>

<p>만약 글쓰기나 회원가입 단계에서 실패할 경우 귀찮게 재입력하지 않도록 포워드를 사용할 수도 있는데 <a href="https://docs.tosspayments.com/blog/redirect">결제 실패 시에 포워드가 아닌 리다이렉트를 사용하는 이유</a>는 무엇일까?</p>

<p><u>포워드는 동일한 요청을 내부에서 다시 처리하기 때문에, 클라이언트가 새로고침을 사용할 경우 에러 위험이 있으며, 내부에서 request 객체를 그대로 넘기므로 이전에 보낸 파라미터가 노출될 수 있기 때문이다.</u></p>

<p>또한, 실패 원인을 정확하게 클라이언트에게 보여줄 수 있다.</p>

<p>다만 단순 글쓰기의 경우, 민감한 정보가 아니기에 포워드를 사용할 수도 있다.</p>

<hr />

<p>실습을 통해 조금 더 친해져 보자.</p>

<p><img src="/assets/images/posts_img/spring/redirect/insert.png" alt="날씨입력" />
<img src="/assets/images/posts_img/spring/redirect/list.png" alt="리다이렉트" /></p>

<h2 id="3-model--controller">3. Model / Controller</h2>

<h3 id="3-1-controller">3-1. Controller</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@RequestMapping</span><span class="o">(</span><span class="s">"/weather-history"</span><span class="o">)</span>
<span class="nd">@Controller</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">WeatherHistoryController</span> <span class="o">{</span>
  
  <span class="nd">@Autowired</span>
  <span class="kd">private</span> <span class="n">weatherHistoryBO</span> <span class="n">weatherHistoryBO</span><span class="o">;</span>
  
  <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/add-view"</span><span class="o">)</span>
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">addView</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="s">"lesson05/addWeather"</span><span class="o">;</span>
  <span class="o">}</span>
  
  <span class="nd">@PostMapping</span><span class="o">(</span><span class="s">"/add"</span><span class="o">)</span>
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">addWeather</span><span class="o">(</span>
      <span class="c1">// @DateTimeFormat(pattern="yyyy-MM-dd") 'date' type 사용 시 convert해줘야 insert 가능</span>
      <span class="c1">// LocalDate 대신 String으로 받아도 자동변환되어 DB에 저장됨</span>
      <span class="c1">// DTO로 받을 경우 DTO class에 annotation!</span>
      <span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"date"</span><span class="o">)</span> <span class="nc">LocalDate</span> <span class="n">date</span><span class="o">,</span>
      <span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"weather"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">weather</span><span class="o">,</span>
      <span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"microDust"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">microDust</span><span class="o">,</span>
      <span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"temperatures"</span><span class="o">)</span> <span class="kt">double</span> <span class="n">temperatures</span><span class="o">,</span>
      <span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"precipitation"</span><span class="o">)</span> <span class="kt">double</span> <span class="n">precipitation</span><span class="o">,</span>
      <span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"windSpeed"</span><span class="o">)</span> <span class="kt">double</span> <span class="n">windSpeed</span><span class="o">,</span>
      <span class="nc">Model</span> <span class="n">model</span><span class="o">)</span> <span class="o">{</span>
    
    <span class="n">weatherHistoryBO</span><span class="o">.</span><span class="na">setWeather</span><span class="o">(</span><span class="n">date</span><span class="o">,</span> <span class="n">weather</span><span class="o">,</span> <span class="n">microDust</span><span class="o">,</span> <span class="n">temperatures</span><span class="o">,</span> <span class="n">precipitation</span><span class="o">,</span> <span class="n">windSpeed</span><span class="o">);</span>
    <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"weather"</span><span class="o">,</span> <span class="n">weather</span><span class="o">);</span>
    
    <span class="c1">// redirect 방법 두 가지</span>
    <span class="c1">// parameter -&gt; HttpServletResponse response</span>
    <span class="c1">// method -&gt; response.sendRedirect("절대경로")</span>
    
    <span class="k">return</span> <span class="s">"redirect:/weather-history/list"</span><span class="o">;</span>
  <span class="o">}</span>
  
  <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/list"</span><span class="o">)</span>
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">weatherList</span><span class="o">(</span><span class="nc">Model</span> <span class="n">model</span><span class="o">)</span> <span class="o">{</span>

    <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Weather</span><span class="o">&gt;</span> <span class="n">weatherHistoryList</span> <span class="o">=</span> <span class="n">weatherHistoryBO</span><span class="o">.</span><span class="na">getWeatherHistoryList</span><span class="o">();</span>

    <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"weatherHistoryList"</span><span class="o">,</span> <span class="n">weatherHistoryList</span><span class="o">);</span>

    <span class="k">return</span> <span class="s">"lesson05/weatherList"</span><span class="o">;</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="3-2-bo">3-2. BO</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Service</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">weatherHistoryBO</span> <span class="o">{</span>

  <span class="nd">@Autowired</span>
  <span class="kd">private</span> <span class="n">weatherHistoryMapper</span> <span class="n">weatherHistoryMapper</span><span class="o">;</span>
  
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setWeather</span><span class="o">(</span>
      <span class="nc">LocalDate</span> <span class="n">date</span><span class="o">,</span> <span class="nc">String</span> <span class="n">weather</span><span class="o">,</span> <span class="nc">String</span> <span class="n">microDust</span><span class="o">,</span> <span class="kt">double</span> <span class="n">temperatures</span><span class="o">,</span> <span class="kt">double</span> <span class="n">precipitation</span><span class="o">,</span> <span class="kt">double</span> <span class="n">windSpeed</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">weatherHistoryMapper</span><span class="o">.</span><span class="na">addWeather</span><span class="o">(</span><span class="n">date</span><span class="o">,</span> <span class="n">weather</span><span class="o">,</span> <span class="n">microDust</span><span class="o">,</span> <span class="n">temperatures</span><span class="o">,</span> <span class="n">precipitation</span><span class="o">,</span> <span class="n">windSpeed</span><span class="o">);</span>
  <span class="o">}</span>
  
  <span class="kd">public</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Weather</span><span class="o">&gt;</span> <span class="nf">getWeatherHistoryList</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">weatherHistoryMapper</span><span class="o">.</span><span class="na">selectWeatherHistoryList</span><span class="o">();</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="3-3-mapper">3-3. Mapper</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Mapper</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">weatherHistoryMapper</span> <span class="o">{</span>

  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">addWeather</span><span class="o">(</span>
      <span class="nd">@Param</span><span class="o">(</span><span class="s">"date"</span><span class="o">)</span> <span class="nc">LocalDate</span> <span class="n">date</span><span class="o">,</span>
      <span class="nd">@Param</span><span class="o">(</span><span class="s">"weather"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">weather</span><span class="o">,</span>
      <span class="nd">@Param</span><span class="o">(</span><span class="s">"microDust"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">microDust</span><span class="o">,</span>
      <span class="nd">@Param</span><span class="o">(</span><span class="s">"temperatures"</span><span class="o">)</span> <span class="kt">double</span> <span class="n">temperatures</span><span class="o">,</span>
      <span class="nd">@Param</span><span class="o">(</span><span class="s">"precipitation"</span><span class="o">)</span> <span class="kt">double</span> <span class="n">precipitation</span><span class="o">,</span>
      <span class="nd">@Param</span><span class="o">(</span><span class="s">"windSpeed"</span><span class="o">)</span> <span class="kt">double</span> <span class="n">windSpeed</span><span class="o">);</span>
  
  <span class="kd">public</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Weather</span><span class="o">&gt;</span> <span class="nf">selectWeatherHistoryList</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="3-4-mapperxml">3-4. Mapper.xml</h3>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cp">&lt;!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"&gt;</span>
<span class="nt">&lt;mapper</span> <span class="na">namespace=</span><span class="s">"com.quiz.lesson05.weatherhistory.weatherHistoryMapper"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;insert</span> <span class="na">id=</span><span class="s">"addWeather"</span> <span class="na">parameterType=</span><span class="s">"com.quiz.lesson05.weatherhistory.Weather"</span><span class="nt">&gt;</span>
    INSERT INTO `weather_history`
    (
      `date`
      ,`weather`
      ,`temperatures`
      ,`precipitation`
      ,`microDust`
      ,`windSpeed`
      ,`createdAt`
      ,`updatedAt`
    )
    VALUES
    (
      #{date}
      ,#{weather}
      ,#{temperatures}
      ,#{precipitation}
      ,#{microDust}
      ,#{windSpeed}
      ,NOW()
      ,NOW()
    )
  <span class="nt">&lt;/insert&gt;</span>
  
  <span class="nt">&lt;select</span> <span class="na">id=</span><span class="s">"selectWeatherHistoryList"</span> <span class="na">resultType=</span><span class="s">"com.quiz.lesson05.weatherhistory.Weather"</span><span class="nt">&gt;</span>
    SELECT
      `id`
      ,`date`
      ,`weather`
      ,`temperatures`
      ,`precipitation`
      ,`microDust`
      ,`windSpeed`
      ,`createdAt`
      ,`updatedAt`
    FROM
      `weather_history`
  <span class="nt">&lt;/select&gt;</span>
  
<span class="nt">&lt;/mapper&gt;</span>
</code></pre></div></div>

<h3 id="3-5-dto">3-5. DTO</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Weather</span> <span class="o">{</span>

  <span class="kd">private</span> <span class="kt">int</span> <span class="n">id</span><span class="o">;</span>
  <span class="kd">private</span> <span class="nc">LocalDate</span> <span class="n">date</span><span class="o">;</span>
  <span class="kd">private</span> <span class="nc">String</span> <span class="n">weather</span><span class="o">;</span>
  <span class="kd">private</span> <span class="kt">double</span> <span class="n">temperatures</span><span class="o">;</span>
  <span class="kd">private</span> <span class="kt">double</span> <span class="n">precipitation</span><span class="o">;</span>
  <span class="kd">private</span> <span class="nc">String</span> <span class="n">microDust</span><span class="o">;</span>
  <span class="kd">private</span>	<span class="kt">double</span> <span class="n">windSpeed</span><span class="o">;</span>
  <span class="kd">private</span> <span class="nc">LocalDateTime</span> <span class="n">createdAT</span><span class="o">;</span>
  <span class="kd">private</span> <span class="nc">LocalDateTime</span> <span class="n">updatedAT</span><span class="o">;</span>
  
  <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getId</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">id</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setId</span><span class="o">(</span><span class="kt">int</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">id</span> <span class="o">=</span> <span class="n">id</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="nc">LocalDate</span> <span class="nf">getDate</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">date</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setDate</span><span class="o">(</span><span class="nc">LocalDate</span> <span class="n">date</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">date</span> <span class="o">=</span> <span class="n">date</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">getWeather</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">weather</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setWeather</span><span class="o">(</span><span class="nc">String</span> <span class="n">weather</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">weather</span> <span class="o">=</span> <span class="n">weather</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">double</span> <span class="nf">getTemperatures</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">temperatures</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setTemperatures</span><span class="o">(</span><span class="kt">double</span> <span class="n">temperatures</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">temperatures</span> <span class="o">=</span> <span class="n">temperatures</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">double</span> <span class="nf">getPrecipitation</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">precipitation</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setPrecipitation</span><span class="o">(</span><span class="kt">double</span> <span class="n">precipitation</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">precipitation</span> <span class="o">=</span> <span class="n">precipitation</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">getMicroDust</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">microDust</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setMicroDust</span><span class="o">(</span><span class="nc">String</span> <span class="n">microDust</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">microDust</span> <span class="o">=</span> <span class="n">microDust</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="nc">Double</span> <span class="nf">getWindSpeed</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">windSpeed</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setWindSpeed</span><span class="o">(</span><span class="nc">Double</span> <span class="n">windSpeed</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">windSpeed</span> <span class="o">=</span> <span class="n">windSpeed</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="nc">LocalDateTime</span> <span class="nf">getCreatedAT</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">createdAT</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setCreatedAT</span><span class="o">(</span><span class="nc">LocalDateTime</span> <span class="n">createdAT</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">createdAT</span> <span class="o">=</span> <span class="n">createdAT</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="nc">LocalDateTime</span> <span class="nf">getUpdatedAT</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">updatedAT</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setUpdatedAT</span><span class="o">(</span><span class="nc">LocalDateTime</span> <span class="n">updatedAT</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">updatedAT</span> <span class="o">=</span> <span class="n">updatedAT</span><span class="o">;</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<hr />

<h2 id="4-view">4. View</h2>

<h3 id="4-1-insert">4-1. Insert</h3>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html</span> <span class="na">xmlns:th=</span><span class="s">"http://www.thymeleaf.org"</span> <span class="na">lang=</span><span class="s">"ko"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head&gt;</span>
    <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;title&gt;&lt;/title&gt;</span>
    <span class="c">&lt;!-- bootstrap --&gt;</span>
    <span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"</span> <span class="na">integrity=</span><span class="s">"sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://code.jquery.com/jquery-3.7.1.js"</span> <span class="na">integrity=</span><span class="s">"sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4="</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;&lt;/script&gt;</span>
    <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"</span> <span class="na">integrity=</span><span class="s">"sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct"</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;&lt;/script&gt;</span>
    <span class="c">&lt;!-- datepicker --&gt;</span>
  <span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://code.jquery.com/ui/1.12.1/jquery-ui.js"</span><span class="nt">&gt;&lt;/script&gt;</span>

<span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">type=</span><span class="s">"text/css"</span> <span class="na">th:href=</span><span class="s">"@{/css/weatherHistoryStyle.css}"</span><span class="nt">&gt;</span>

<span class="c">&lt;!-- 구글링한 datepicker 그대로 적용 --&gt;</span>
<span class="nt">&lt;script&gt;</span>
  <span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
      <span class="c1">//input을 datepicker로 선언</span>
      <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#date</span><span class="dl">"</span><span class="p">).</span><span class="nx">datepicker</span><span class="p">({</span>
          <span class="na">dateFormat</span><span class="p">:</span> <span class="dl">'</span><span class="s1">yy-mm-dd</span><span class="dl">'</span> <span class="c1">//달력 날짜 형태</span>
          <span class="p">,</span><span class="na">showOtherMonths</span><span class="p">:</span> <span class="kc">true</span> <span class="c1">//빈 공간에 현재월의 앞뒤월의 날짜를 표시</span>
          <span class="p">,</span><span class="na">showMonthAfterYear</span><span class="p">:</span><span class="kc">true</span> <span class="c1">// 월- 년 순서가아닌 년도 - 월 순서</span>
          <span class="p">,</span><span class="na">changeYear</span><span class="p">:</span> <span class="kc">true</span> <span class="c1">//option값 년 선택 가능</span>
          <span class="p">,</span><span class="na">changeMonth</span><span class="p">:</span> <span class="kc">true</span> <span class="c1">//option값  월 선택 가능                </span>
          <span class="p">,</span><span class="na">showOn</span><span class="p">:</span> <span class="dl">"</span><span class="s2">both</span><span class="dl">"</span> <span class="c1">//button:버튼을 표시하고,버튼을 눌러야만 달력 표시 ^ both:버튼을 표시하고,버튼을 누르거나 input을 클릭하면 달력 표시  </span>
          <span class="p">,</span><span class="na">buttonImage</span><span class="p">:</span> <span class="dl">"</span><span class="s2">http://jqueryui.com/resources/demos/datepicker/images/calendar.gif</span><span class="dl">"</span> <span class="c1">//버튼 이미지 경로</span>
          <span class="p">,</span><span class="na">buttonImageOnly</span><span class="p">:</span> <span class="kc">true</span> <span class="c1">//버튼 이미지만 깔끔하게 보이게함</span>
          <span class="p">,</span><span class="na">buttonText</span><span class="p">:</span> <span class="dl">"</span><span class="s2">선택</span><span class="dl">"</span> <span class="c1">//버튼 호버 텍스트              </span>
          <span class="p">,</span><span class="na">yearSuffix</span><span class="p">:</span> <span class="dl">"</span><span class="s2">년</span><span class="dl">"</span> <span class="c1">//달력의 년도 부분 뒤 텍스트</span>
          <span class="p">,</span><span class="na">monthNamesShort</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">1월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">2월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">3월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">4월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">5월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">6월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">7월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">8월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">9월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">10월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">11월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">12월</span><span class="dl">'</span><span class="p">]</span> <span class="c1">//달력의 월 부분 텍스트</span>
          <span class="p">,</span><span class="na">monthNames</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">1월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">2월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">3월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">4월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">5월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">6월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">7월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">8월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">9월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">10월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">11월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">12월</span><span class="dl">'</span><span class="p">]</span> <span class="c1">//달력의 월 부분 Tooltip</span>
          <span class="p">,</span><span class="na">dayNamesMin</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">일</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">월</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">화</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">수</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">목</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">금</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">토</span><span class="dl">'</span><span class="p">]</span> <span class="c1">//달력의 요일 텍스트</span>
          <span class="p">,</span><span class="na">dayNames</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">일요일</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">월요일</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">화요일</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">수요일</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">목요일</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">금요일</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">토요일</span><span class="dl">'</span><span class="p">]</span> <span class="c1">//달력의 요일 Tooltip</span>
          <span class="cm">/*  ,minDate: "-5Y" //최소 선택일자(-1D:하루전, -1M:한달전, -1Y:일년전)
          ,maxDate: "+5y" //최대 선택일자(+1D:하루후, -1M:한달후, -1Y:일년후)   */</span>
      <span class="p">});</span>                    
      
      <span class="c1">//초기값을 오늘 날짜로 설정해줘야 합니다.</span>
      <span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">#date</span><span class="dl">'</span><span class="p">).</span><span class="nx">datepicker</span><span class="p">(</span><span class="dl">'</span><span class="s1">setDate</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">today</span><span class="dl">'</span><span class="p">);</span> <span class="c1">//(-1D:하루전, -1M:한달전, -1Y:일년전), (+1D:하루후, -1M:한달후, -1Y:일년후)            </span>
  <span class="p">});</span>
<span class="nt">&lt;/script&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"wrap"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"contents d-flex"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;nav</span> <span class="na">class=</span><span class="s">"col-2"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"logo d-flex justify-content-center mt-3"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Emblem_of_the_Government_of_the_Republic_of_Korea.svg/800px-Emblem_of_the_Government_of_the_Republic_of_Korea.svg.png"</span> <span class="na">width=</span><span class="s">"25"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"text-white font-weight-bold ml-2"</span><span class="nt">&gt;</span>기상청<span class="nt">&lt;/span&gt;</span>
      <span class="nt">&lt;/div&gt;</span>
      
      <span class="c">&lt;!-- flex-column: 세로 메뉴 --&gt;</span>
      <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav flex-column mt-4"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"nav-item"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"/weather-history/list"</span> <span class="na">class=</span><span class="s">"nav-link menu-font"</span><span class="nt">&gt;</span>날씨<span class="nt">&lt;/a&gt;</span>
        <span class="nt">&lt;/li&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"nav-item"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"/weather-history/add"</span> <span class="na">class=</span><span class="s">"nav-link menu-font"</span><span class="nt">&gt;</span>날씨입력<span class="nt">&lt;/a&gt;</span>
        <span class="nt">&lt;/li&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"nav-item"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"nav-link menu-font"</span><span class="nt">&gt;</span>테마날씨<span class="nt">&lt;/a&gt;</span>
        <span class="nt">&lt;/li&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"nav-item"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"nav-link menu-font"</span><span class="nt">&gt;</span>관측 기후<span class="nt">&lt;/a&gt;</span>
        <span class="nt">&lt;/li&gt;</span>
      <span class="nt">&lt;/ul&gt;</span>
    <span class="nt">&lt;/nav&gt;</span>
    
    <span class="nt">&lt;section</span> <span class="na">class=</span><span class="s">"col-10 mt-3 ml-5"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;h3&gt;</span>날씨 추가<span class="nt">&lt;/h3&gt;</span>
      
      <span class="nt">&lt;form</span> <span class="na">method=</span><span class="s">"post"</span> <span class="na">action=</span><span class="s">"/weather-history/add"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"d-flex justify-content-between mt-5"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"d-flex align-items-center"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-label"</span><span class="nt">&gt;</span>날짜<span class="nt">&lt;/div&gt;</span>
            <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">id=</span><span class="s">"date"</span> <span class="na">name=</span><span class="s">"date"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;/div&gt;</span>
          <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"d-flex align-items-center"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-label"</span><span class="nt">&gt;</span>날씨<span class="nt">&lt;/div&gt;</span>
            <span class="nt">&lt;select</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">name=</span><span class="s">"weather"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;option&gt;</span>맑음<span class="nt">&lt;/option&gt;</span>
              <span class="nt">&lt;option&gt;</span>구름조금<span class="nt">&lt;/option&gt;</span>
              <span class="nt">&lt;option&gt;</span>흐림<span class="nt">&lt;/option&gt;</span>
              <span class="nt">&lt;option&gt;</span>비<span class="nt">&lt;/option&gt;</span>
            <span class="nt">&lt;/select&gt;</span>
          <span class="nt">&lt;/div&gt;</span>

          <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"d-flex align-items-center"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-label"</span><span class="nt">&gt;</span>미세먼지<span class="nt">&lt;/div&gt;</span>
            <span class="nt">&lt;select</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">name=</span><span class="s">"microDust"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;option&gt;</span>좋음<span class="nt">&lt;/option&gt;</span>
              <span class="nt">&lt;option&gt;</span>보통<span class="nt">&lt;/option&gt;</span>
              <span class="nt">&lt;option&gt;</span>나쁨<span class="nt">&lt;/option&gt;</span>
              <span class="nt">&lt;option&gt;</span>최악<span class="nt">&lt;/option&gt;</span>
            <span class="nt">&lt;/select&gt;</span>
          <span class="nt">&lt;/div&gt;</span>
        <span class="nt">&lt;/div&gt;</span>

        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"d-flex justify-content-between mt-5"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"d-flex align-items-center"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-label"</span><span class="nt">&gt;</span>기온<span class="nt">&lt;/div&gt;</span>
            <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">name=</span><span class="s">"temperatures"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group-append"</span><span class="nt">&gt;</span>
                <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-text"</span><span class="nt">&gt;</span>℃<span class="nt">&lt;/span&gt;</span>
              <span class="nt">&lt;/div&gt;</span>
            <span class="nt">&lt;/div&gt;</span>
          <span class="nt">&lt;/div&gt;</span>
          <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"d-flex align-items-center"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-label"</span><span class="nt">&gt;</span>강수량<span class="nt">&lt;/div&gt;</span>
            <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">name=</span><span class="s">"precipitation"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group-append"</span><span class="nt">&gt;</span>
                <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-text"</span><span class="nt">&gt;</span>mm<span class="nt">&lt;/span&gt;</span>
              <span class="nt">&lt;/div&gt;</span>
            <span class="nt">&lt;/div&gt;</span>
          <span class="nt">&lt;/div&gt;</span>

          <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"d-flex align-items-center"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-label"</span><span class="nt">&gt;</span>풍속<span class="nt">&lt;/div&gt;</span>
            <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">name=</span><span class="s">"windSpeed"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group-append"</span><span class="nt">&gt;</span>
                <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-text"</span><span class="nt">&gt;</span>km/h<span class="nt">&lt;/span&gt;</span>
              <span class="nt">&lt;/div&gt;</span>
            <span class="nt">&lt;/div&gt;</span>
          <span class="nt">&lt;/div&gt;</span>
        <span class="nt">&lt;/div&gt;</span>
        
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"text-right mt-4 mb-5"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"submit"</span> <span class="na">class=</span><span class="s">"btn btn-success"</span> <span class="na">value=</span><span class="s">"저장"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;/div&gt;</span>
      <span class="nt">&lt;/form&gt;</span>
    <span class="nt">&lt;/section&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;footer</span> <span class="na">class=</span><span class="s">"d-flex align-items-center"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div&gt;</span>
      <span class="nt">&lt;img</span> <span class="na">class=</span><span class="s">"foot-logo-image"</span> <span class="na">src=</span><span class="s">"https://www.weather.go.kr/w/resources/image/foot_logo.png"</span> <span class="na">width=</span><span class="s">"120"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;div&gt;</span>
      <span class="nt">&lt;small</span> <span class="na">class=</span><span class="s">"text-secondary"</span><span class="nt">&gt;</span> 
        (07062) 서울시 동작구 여의대방로16길 61 <span class="nt">&lt;br&gt;</span>
        Copyright@2025 KMA. All Rights RESERVED.
      <span class="nt">&lt;/small&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;/footer&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<h3 id="4-2-list-redirect">4-2. List (redirect)</h3>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html</span> <span class="na">xmlns:th=</span><span class="s">"http://www.thymeleaf.org"</span> <span class="na">lang=</span><span class="s">"ko"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head&gt;</span>
    <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;title&gt;&lt;/title&gt;</span>
    <span class="c">&lt;!-- bootstrap --&gt;</span>
    <span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"</span> <span class="na">integrity=</span><span class="s">"sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://code.jquery.com/jquery-3.7.1.js"</span> <span class="na">integrity=</span><span class="s">"sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4="</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;&lt;/script&gt;</span>
    <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"</span> <span class="na">integrity=</span><span class="s">"sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct"</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;&lt;/script&gt;</span>
    
    <span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">type=</span><span class="s">"text/css"</span> <span class="na">th:href=</span><span class="s">"@{/css/weather-history/style.css}"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"wrap"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"contents d-flex"</span><span class="nt">&gt;</span>
    <span class="c">&lt;!-- 메뉴 영역 --&gt;</span>
    <span class="nt">&lt;nav</span> <span class="na">class=</span><span class="s">"col-2"</span><span class="nt">&gt;</span>
      <span class="c">&lt;!-- 상단 로고 --&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"logo d-flex justify-content-center mt-3"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Emblem_of_the_Government_of_the_Republic_of_Korea.svg/800px-Emblem_of_the_Government_of_the_Republic_of_Korea.svg.png"</span> <span class="na">width=</span><span class="s">"25"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"text-white font-weight-bold ml-2"</span><span class="nt">&gt;</span>기상청<span class="nt">&lt;/span&gt;</span>
      <span class="nt">&lt;/div&gt;</span>

      <span class="c">&lt;!-- 메뉴 --&gt;</span>
      <span class="c">&lt;!-- flex-column: 세로 메뉴 --&gt;</span>
      <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav flex-column mt-4"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"nav-item"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"/weather-history/weather-list-view"</span> <span class="na">class=</span><span class="s">"nav-link menu-font"</span><span class="nt">&gt;</span>날씨<span class="nt">&lt;/a&gt;</span>
        <span class="nt">&lt;/li&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"nav-item"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"/weather-history/add-weather-view"</span> <span class="na">class=</span><span class="s">"nav-link menu-font"</span><span class="nt">&gt;</span>날씨입력<span class="nt">&lt;/a&gt;</span>
        <span class="nt">&lt;/li&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"nav-item"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"nav-link menu-font"</span><span class="nt">&gt;</span>테마날씨<span class="nt">&lt;/a&gt;</span>
        <span class="nt">&lt;/li&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"nav-item"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"nav-link menu-font"</span><span class="nt">&gt;</span>관측 기후<span class="nt">&lt;/a&gt;</span>
        <span class="nt">&lt;/li&gt;</span>
      <span class="nt">&lt;/ul&gt;</span>
    <span class="nt">&lt;/nav&gt;</span>

    <span class="c">&lt;!-- 날씨 히스토리 --&gt;</span>
    <span class="nt">&lt;section</span> <span class="na">class=</span><span class="s">"weather-history col-10 mt-3 ml-5"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;h3&gt;</span>과거 날씨<span class="nt">&lt;/h3&gt;</span>
      
      <span class="nt">&lt;table</span> <span class="na">class=</span><span class="s">"table text-center"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;thead&gt;</span>
          <span class="nt">&lt;tr&gt;</span>
            <span class="nt">&lt;th&gt;</span>날짜<span class="nt">&lt;/th&gt;</span>
            <span class="nt">&lt;th&gt;</span>날씨<span class="nt">&lt;/th&gt;</span>
            <span class="nt">&lt;th&gt;</span>기온<span class="nt">&lt;/th&gt;</span>
            <span class="nt">&lt;th&gt;</span>강수량<span class="nt">&lt;/th&gt;</span>
            <span class="nt">&lt;th&gt;</span>미세먼지<span class="nt">&lt;/th&gt;</span>
            <span class="nt">&lt;th&gt;</span>풍속<span class="nt">&lt;/th&gt;</span>
          <span class="nt">&lt;/tr&gt;</span>
        <span class="nt">&lt;/thead&gt;</span>
        <span class="nt">&lt;tbody&gt;</span>
          <span class="nt">&lt;tr</span> <span class="na">th:each=</span><span class="s">"history : ${weatherHistoryList}"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${#temporals.format(history.date, 'yyyy년 M월 d일')}"</span><span class="nt">&gt;&lt;/td&gt;</span>
            <span class="nt">&lt;td</span> <span class="na">th:switch=</span><span class="s">"${history.weather}"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;img</span> <span class="na">th:case=</span><span class="s">"'맑음'"</span> <span class="na">src=</span><span class="s">"/img/sunny.jpg"</span> <span class="na">alt=</span><span class="s">"맑음"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;img</span> <span class="na">th:case=</span><span class="s">"'비'"</span> <span class="na">src=</span><span class="s">"/img/rainy.jpg"</span> <span class="na">alt=</span><span class="s">"비"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;img</span> <span class="na">th:case=</span><span class="s">"'구름조금'"</span> <span class="na">src=</span><span class="s">"/img/partlyCloudy.jpg"</span> <span class="na">alt=</span><span class="s">"구름조금"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;img</span> <span class="na">th:case=</span><span class="s">"'흐림'"</span> <span class="na">src=</span><span class="s">"/img/cloudy.jpg"</span> <span class="na">alt=</span><span class="s">"흐림"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;span</span> <span class="na">th:case=</span><span class="s">"*"</span> <span class="na">th:text=</span><span class="s">"${history.weather}"</span><span class="nt">&gt;&lt;/span&gt;</span>
            <span class="nt">&lt;/td&gt;</span>
            <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"|${history.temperatures}°C|"</span><span class="nt">&gt;&lt;/td&gt;</span>
            <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"|${history.precipitation}mm|"</span><span class="nt">&gt;&lt;/td&gt;</span>
            <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${history.microDust}"</span><span class="nt">&gt;&lt;/td&gt;</span>
            <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${history.windSpeed} + 'km/h'"</span><span class="nt">&gt;&lt;/td&gt;</span>
          <span class="nt">&lt;/tr&gt;</span>
        <span class="nt">&lt;/tbody&gt;</span>
      <span class="nt">&lt;/table&gt;</span>
    <span class="nt">&lt;/section&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;footer</span> <span class="na">class=</span><span class="s">"d-flex align-items-center"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"footer-logo ml-4"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;img</span> <span class="na">class=</span><span class="s">"foot-logo-image"</span> <span class="na">src=</span><span class="s">"https://www.weather.go.kr/w/resources/image/foot_logo.png"</span> <span class="na">width=</span><span class="s">"120"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"copyright ml-4"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;small</span> <span class="na">class=</span><span class="s">"text-secondary"</span><span class="nt">&gt;</span> 
        (07062) 서울시 동작구 여의대방로16길 61 <span class="nt">&lt;br&gt;</span>
        Copyright@20XX KMA. All Rights RESERVED.
      <span class="nt">&lt;/small&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;/footer&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>]]></content><author><name>gilhanbit</name><email>rlaqnwksp@gmail.com</email></author><category term="Spring" /><category term="spring" /><category term="redirect" /><category term="foward" /><summary type="html"><![CDATA[redirect를 하는 이유와 foward와의 차이]]></summary></entry><entry><title type="html">[Spring] MVC Cycle 복습</title><link href="https://gilhanbit.github.io/categories4/mvccycle/" rel="alternate" type="text/html" title="[Spring] MVC Cycle 복습" /><published>2025-05-06T00:00:00+00:00</published><updated>2025-05-06T00:00:00+00:00</updated><id>https://gilhanbit.github.io/categories4/spring-mvccycle</id><content type="html" xml:base="https://gilhanbit.github.io/categories4/mvccycle/"><![CDATA[<h2 id="1-mvc">1. MVC</h2>

<blockquote>
  <p>Model-View-Controller</p>
</blockquote>

<p>웹개발에서 <strong><font color="##000099">구조를 역할별로 분리해서 보다 효율적으로 개발, 유지보수를 하기 위해 사용</font></strong>한다.</p>

<p><u>처리 흐름으로 보면 View-Controller-Model</u>인데, MVC가 아니라 VCM이 맞는 거 아닐까 싶었다.</p>

<p><strong>그런데 왜 MVC라 부를까?</strong></p>

<p>결론부터 말하자면 <strong>MVC는 처리 흐름이 아니라 관계 구조의 명칭</strong>이다.</p>

<p>controller가 중심이 되어 model과 view를 관리하는 구조다.</p>

<p>즉, <code class="language-plaintext highlighter-rouge">model</code>과 <code class="language-plaintext highlighter-rouge">view</code>를 <code class="language-plaintext highlighter-rouge">controller</code>가 <strong>연결하고 제어한다는 의미</strong>에서 MVC라 부른다고 한다.</p>

<ol>
  <li>view: 사용자가 입력, 버튼 클릭 -&gt; 요청 발생</li>
  <li>controller: 요청을 받아 해석</li>
  <li>model: 필요한 데이터 로직 실행</li>
  <li>controller: 결과를 다시 view에 전달</li>
  <li>view: 클라이언트에게 출력</li>
</ol>

<hr />

<h2 id="2-model">2. Model</h2>

<ul>
  <li>데이터, 비지니스 로직 담당</li>
  <li>DB와 연동 및 연산 처리</li>
</ul>

<p><strong>spring MVC</strong>에서 <strong><font color="#000099">model은 데이터와 비지니스 로직을 담당하는 핵심 요소</font></strong>로 <strong>실무에서는 DTO, service, repository 등으로 세분화 시켜 사용</strong>한다.</p>

<p>이렇게 model을 세분화 하는 이유는, 책임을 분산-강화 시키고 협업과 유지보수를 원활하게 하기 위함이다.</p>

<h3 id="2-1-entity-dto를-분리하는-이유">2-1. Entity, DTO를 분리하는 이유</h3>

<p><strong>엔터티는 DB 스키마와 1:1 매칭</strong>되므로 <strong><font color="#990000">API 응답에 엔터티를 직접 리턴하면 보안 문제가 발생할 수 있다.</font></strong></p>

<p>즉 DTO를 사용하는 이유는 필요한 데이터만 포함하고 유연한 유지보수를 위해서다.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">seller</span> <span class="o">{</span>

  <span class="kd">private</span> <span class="nc">String</span> <span class="n">nickname</span><span class="o">;</span>
  <span class="kd">private</span> <span class="nc">String</span> <span class="n">profileImgUrl</span><span class="o">;</span>
  <span class="kd">private</span> <span class="nc">Double</span> <span class="n">temperature</span><span class="o">;</span>
  
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">getNickname</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">nickname</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setNickname</span><span class="o">(</span><span class="nc">String</span> <span class="n">nickname</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">nickname</span> <span class="o">=</span> <span class="n">nickname</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">getProfileImgUrl</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">profileImgUrl</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setProfileImgUrl</span><span class="o">(</span><span class="nc">String</span> <span class="n">profileImgUrl</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">profileImgUrl</span> <span class="o">=</span> <span class="n">profileImgUrl</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="nc">Double</span> <span class="nf">getTemperature</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">temperature</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setTemperature</span><span class="o">(</span><span class="nc">Double</span> <span class="n">temperature</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">temperature</span> <span class="o">=</span> <span class="n">temperature</span><span class="o">;</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="2-2-service를-사용하는-이유">2-2. Service를 사용하는 이유</h3>

<p>controller에서 직접 repository를 호출하지 않고 service를 사용하는 이유가 있는데, 만약 controller에서 repository를 직접 호출한다면?</p>

<ol>
  <li>컨트롤러가 비지니스 로직을 갖게 된다.
    <ol>
      <li>컨트롤러는 요청을 받아 모델에 전달하고 그 결과를 뷰로 리턴하는 역할이다. 그러나 컨트롤러에서 직접 레퍼지토리에서 데이터를 가져오는 역할까지 하게되면 컨트롤러의 책임이 커지고 유지보수가 어려워진다.</li>
    </ol>
  </li>
  <li>비지니스 로직을 추가하기 어렵다.
    <ol>
      <li>컨트롤러에 직접 로직을 추가할 경우 다른 API에서 동일한 로직이 필요한 경우 중복 코드가 많아진다. 때문에 유지보수가 어렵고 비지니스 로직이 흘어져 코드의 일관성이 깨지게 된다.</li>
    </ol>
  </li>
</ol>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Service</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">sellerBO</span> <span class="o">{</span>
  
  <span class="nd">@Autowired</span>
  <span class="kd">private</span> <span class="nc">SellerMapper</span> <span class="n">sellerMapper</span><span class="o">;</span>
  
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">insertSeller</span><span class="o">(</span><span class="nc">String</span> <span class="n">nickname</span><span class="o">,</span> <span class="nc">String</span> <span class="n">profileImgUrl</span><span class="o">,</span> <span class="nc">Double</span> <span class="n">temperature</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">sellerMapper</span><span class="o">.</span><span class="na">insertSeller</span><span class="o">(</span><span class="n">nickname</span><span class="o">,</span> <span class="n">profileImgUrl</span><span class="o">,</span> <span class="n">temperature</span><span class="o">);</span>
  <span class="o">}</span>
  
  <span class="kd">public</span> <span class="n">seller</span> <span class="nf">sellerInfoView</span><span class="o">(</span><span class="nc">Integer</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">id</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
      <span class="k">return</span> <span class="n">sellerMapper</span><span class="o">.</span><span class="na">sellerInfoView</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
      <span class="k">return</span> <span class="n">sellerMapper</span><span class="o">.</span><span class="na">sellerInfoSearch</span><span class="o">(</span><span class="n">id</span><span class="o">);</span>
    <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="2-3-repository를-분리하는-이유">2-3. Repository를 분리하는 이유</h3>

<p>데이터 접근을 추상화하여 유지보수성을 높이기 위함이 목적이다.</p>

<p>서비스가 레퍼지토리를 통해 데이터를 가져오면, DB가 바뀌어도 서비스 로직을 그대로 유지할 수 있다.</p>

<p>즉 JPA, MyBatis 등 다양한 방식으로 쉽게 변경이 가능하다.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Mapper</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">SellerMapper</span> <span class="o">{</span>

  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">insertSeller</span><span class="o">(</span>
      <span class="nd">@Param</span><span class="o">(</span><span class="s">"nickname"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">nickname</span><span class="o">,</span>
      <span class="nd">@Param</span><span class="o">(</span><span class="s">"profileImgUrl"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">profileImgUrl</span><span class="o">,</span>
      <span class="nd">@Param</span><span class="o">(</span><span class="s">"temperature"</span><span class="o">)</span> <span class="nc">Double</span> <span class="n">temperature</span><span class="o">);</span>
  
  <span class="kd">public</span> <span class="n">seller</span> <span class="nf">sellerInfoView</span><span class="o">();</span>
  
  <span class="kd">public</span> <span class="n">seller</span> <span class="nf">sellerInfoSearch</span><span class="o">(</span><span class="nc">Integer</span> <span class="n">id</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cp">&lt;!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"&gt;</span>

<span class="nt">&lt;mapper</span> <span class="na">namespace=</span><span class="s">"com.quiz.seller.mapper.SellerMapper"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;insert</span> <span class="na">id=</span><span class="s">"insertSeller"</span> <span class="na">parameterType=</span><span class="s">"map"</span><span class="nt">&gt;</span>
    INSERT INTO `seller`
    (
      `nickname`
      ,`profileImgUrl`
      ,`temperature`
      ,`createdAt`
      ,`updatedAt`
    )
    VALUES
    (
      #{nickname}
      ,#{profileImgUrl}
      ,#{temperature}
      ,NOW()
      ,NOW()
    )
  <span class="nt">&lt;/insert&gt;</span>
  
  <span class="nt">&lt;select</span> <span class="na">id=</span><span class="s">"sellerInfoView"</span> <span class="na">resultType=</span><span class="s">"com.quiz.seller.domain.seller"</span><span class="nt">&gt;</span>
    SELECT
      `nickname`
      ,`profileImgUrl`
      ,`temperature`
    FROM
      `seller`
    ORDER BY
      `id`
    DESC LIMIT
      1
  <span class="nt">&lt;/select&gt;</span>
  
  <span class="nt">&lt;select</span> <span class="na">id=</span><span class="s">"sellerInfoSearch"</span> <span class="na">resultType=</span><span class="s">"com.quiz.seller.domain.seller"</span><span class="nt">&gt;</span>
    SELECT
      `nickname`
      ,`profileImgUrl`
      ,`temperature`
    FROM
      `seller`
    WHERE
      `id` = #{id}
  <span class="nt">&lt;/select&gt;</span>
<span class="nt">&lt;/mapper&gt;</span>
</code></pre></div></div>

<hr />

<h2 id="3-view">3. View</h2>

<ul>
  <li>클라이언트가 보는 화면</li>
  <li>클라이언트의 입력을 받아 controller에 전달</li>
  <li>모델의 데이터를 출력</li>
</ul>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html</span> <span class="na">xmlns:th=</span><span class="s">"http://www.thymeleaf.org"</span> <span class="na">lang=</span><span class="s">"ko"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">&gt;</span>
<span class="nt">&lt;title&gt;</span>판매자 추가<span class="nt">&lt;/title&gt;</span>
  <span class="c">&lt;!-- bootstrap --&gt;</span>
  <span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"</span> <span class="na">integrity=</span><span class="s">"sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://code.jquery.com/jquery-3.7.1.js"</span> <span class="na">integrity=</span><span class="s">"sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4="</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;&lt;/script&gt;</span>
  <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"</span> <span class="na">integrity=</span><span class="s">"sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct"</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;h1&gt;</span>판매자 추가<span class="nt">&lt;/h1&gt;</span>
    <span class="nt">&lt;form</span> <span class="na">method=</span><span class="s">"post"</span> <span class="na">action=</span><span class="s">"/seller/afterAdd"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"nickname"</span><span class="nt">&gt;</span>닉네임<span class="nt">&lt;/label&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">id=</span><span class="s">"nickname"</span> <span class="na">name=</span><span class="s">"nickname"</span> <span class="na">class=</span><span class="s">"form-control col-4"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;/div&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"profileImgUrl"</span><span class="nt">&gt;</span>프로필 사진<span class="nt">&lt;/label&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">id=</span><span class="s">"profileImgUrl"</span> <span class="na">name=</span><span class="s">"profileImgUrl"</span> <span class="na">class=</span><span class="s">"form-control"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;/div&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"temperature"</span><span class="nt">&gt;</span>매너 온도<span class="nt">&lt;/label&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">id=</span><span class="s">"temperature"</span> <span class="na">name=</span><span class="s">"temperature"</span> <span class="na">class=</span><span class="s">"form-control col-4"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;/div&gt;</span>
      
      <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"submit"</span> <span class="na">value=</span><span class="s">"추가"</span> <span class="na">class=</span><span class="s">"btn btn-primary"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/form&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html</span> <span class="na">xmlns:th=</span><span class="s">"http://www.thymeleaf.org"</span> <span class="na">lang=</span><span class="s">"ko"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">&gt;</span>
<span class="nt">&lt;title&gt;</span>판매자 정보<span class="nt">&lt;/title&gt;</span>
  <span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"</span> <span class="na">integrity=</span><span class="s">"sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://code.jquery.com/jquery-3.7.1.js"</span> <span class="na">integrity=</span><span class="s">"sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4="</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;&lt;/script&gt;</span>
  <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"</span> <span class="na">integrity=</span><span class="s">"sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct"</span> <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;h1&gt;</span>판매자 정보<span class="nt">&lt;/h1&gt;</span>
    <span class="nt">&lt;img</span> <span class="na">th:src=</span><span class="s">"${seller.profileImgUrl}"</span> <span class="na">width=</span><span class="s">"200"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"h1"</span> <span class="na">th:text=</span><span class="s">"${seller.nickname}"</span><span class="nt">&gt;&lt;/div&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"text-warning h3 font-weight-bold"</span> <span class="na">th:text=</span><span class="s">"${seller.temperature}"</span><span class="nt">&gt;&lt;/div&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<hr />

<h2 id="4-controller">4. Controller</h2>

<ul>
  <li>model-view를 연결</li>
  <li>클라이언트의 요청을 model에 전달</li>
  <li>model의 데이터를 view에 전달</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@RequestMapping</span><span class="o">(</span><span class="s">"/seller"</span><span class="o">)</span>
<span class="nd">@Controller</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SellerController</span> <span class="o">{</span>
	
	<span class="nd">@Autowired</span>
	<span class="kd">private</span> <span class="n">sellerBO</span> <span class="n">sellerBO</span><span class="o">;</span>
	
	<span class="nd">@RequestMapping</span><span class="o">(</span><span class="s">"/add"</span><span class="o">)</span>
	<span class="kd">public</span> <span class="nc">String</span> <span class="nf">addSellerView</span><span class="o">()</span> <span class="o">{</span>
		<span class="k">return</span> <span class="s">"seller/addSeller"</span><span class="o">;</span>
	<span class="o">}</span>
	
	<span class="nd">@PostMapping</span><span class="o">(</span><span class="s">"/afterAdd"</span><span class="o">)</span>
	<span class="kd">public</span> <span class="nc">String</span> <span class="nf">addSeller</span><span class="o">(</span>
			<span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"nickname"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">nickname</span><span class="o">,</span>
			<span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"profileImgUrl"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">profileImgUrl</span><span class="o">,</span>
			<span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"temperature"</span><span class="o">)</span> <span class="nc">Double</span> <span class="n">temperature</span><span class="o">)</span> <span class="o">{</span>
		
		<span class="n">sellerBO</span><span class="o">.</span><span class="na">insertSeller</span><span class="o">(</span><span class="n">nickname</span><span class="o">,</span> <span class="n">profileImgUrl</span><span class="o">,</span> <span class="n">temperature</span><span class="o">);</span>
		
		<span class="k">return</span> <span class="s">"seller/afterAddSeller"</span><span class="o">;</span>
	<span class="o">}</span>
	
	<span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/info"</span><span class="o">)</span>
	<span class="kd">public</span> <span class="nc">String</span> <span class="nf">sellerInfoView</span><span class="o">(</span>
			<span class="nd">@RequestParam</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="s">"id"</span><span class="o">,</span> <span class="n">required</span> <span class="o">=</span> <span class="kc">false</span><span class="o">)</span> <span class="nc">Integer</span> <span class="n">id</span><span class="o">,</span>
			<span class="nc">Model</span> <span class="n">model</span><span class="o">)</span> <span class="o">{</span>
		
		<span class="n">seller</span> <span class="n">seller</span> <span class="o">=</span> <span class="n">sellerBO</span><span class="o">.</span><span class="na">sellerInfoView</span><span class="o">(</span><span class="n">id</span><span class="o">);</span>
		<span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"seller"</span><span class="o">,</span> <span class="n">seller</span><span class="o">);</span>
		
		<span class="k">return</span> <span class="s">"seller/sellerInfo"</span><span class="o">;</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<hr />

<p><strong>참고</strong></p>

<ul>
  <li><a href="https://velog.io/@chlek95/Spring-MVC-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%9D%90%EB%A6%84-Entity-DTO-Controller-Service-Repository">참고</a></li>
</ul>]]></content><author><name>gilhanbit</name><email>rlaqnwksp@gmail.com</email></author><category term="Spring" /><category term="spring" /><category term="mvccycle" /><summary type="html"><![CDATA[MVC와 더 친해지기]]></summary></entry><entry><title type="html">[Baekjoon] 반복문</title><link href="https://gilhanbit.github.io/baekjoon/step3/" rel="alternate" type="text/html" title="[Baekjoon] 반복문" /><published>2025-05-04T00:00:00+00:00</published><updated>2025-05-04T00:00:00+00:00</updated><id>https://gilhanbit.github.io/baekjoon/baekjoon-step3</id><content type="html" xml:base="https://gilhanbit.github.io/baekjoon/step3/"><![CDATA[<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">baekjoon</span><span class="o">;</span>

<span class="kn">import</span> <span class="nn">java.io.BufferedReader</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.BufferedWriter</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.IOException</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.InputStreamReader</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.OutputStreamWriter</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.Scanner</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.StringTokenizer</span><span class="o">;</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Step03</span> <span class="o">{</span>

  <span class="kd">private</span> <span class="kd">static</span> <span class="nc">String</span> <span class="nc">String</span><span class="o">;</span>

  <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">NumberFormatException</span><span class="o">,</span> <span class="nc">IOException</span> <span class="o">{</span>
    
    <span class="nc">Scanner</span> <span class="n">scan</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Scanner</span><span class="o">(</span><span class="nc">System</span><span class="o">.</span><span class="na">in</span><span class="o">);</span>
    <span class="nc">StringTokenizer</span> <span class="n">st</span><span class="o">;</span>
    <span class="nc">BufferedReader</span> <span class="n">br</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">BufferedReader</span> <span class="o">(</span><span class="k">new</span> <span class="nc">InputStreamReader</span><span class="o">(</span><span class="nc">System</span><span class="o">.</span><span class="na">in</span><span class="o">));</span>
    <span class="nc">BufferedWriter</span> <span class="n">bw</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">BufferedWriter</span> <span class="o">(</span><span class="k">new</span> <span class="nc">OutputStreamWriter</span><span class="o">(</span><span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">));</span>
    
    <span class="c1">// https://www.acmicpc.net/problem/2739</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"구구단"</span><span class="o">);</span>
    <span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="n">scan</span><span class="o">.</span><span class="na">nextInt</span><span class="o">();</span>
    
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
      <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">a</span> <span class="o">+</span> <span class="s">" X "</span> <span class="o">+</span> <span class="n">i</span> <span class="o">+</span> <span class="s">" = "</span> <span class="o">+</span> <span class="o">(</span><span class="n">a</span> <span class="o">*</span> <span class="n">i</span><span class="o">));</span>
    <span class="o">}</span>
    
    <span class="c1">// https://www.acmicpc.net/problem/8393</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"입력 값까지의 합 구하기"</span><span class="o">);</span>
    <span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="n">scan</span><span class="o">.</span><span class="na">nextInt</span><span class="o">();</span>
    
    <span class="kt">int</span> <span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">b</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
      <span class="n">sum</span> <span class="o">+=</span> <span class="n">i</span><span class="o">;</span>
    <span class="o">}</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">sum</span><span class="o">);</span>
    
    <span class="c1">// https://www.acmicpc.net/problem/25304</span>
    <span class="kt">int</span> <span class="n">totalPrice</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">br</span><span class="o">.</span><span class="na">readLine</span><span class="o">());</span>
    <span class="kt">int</span> <span class="n">totalCount</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">br</span><span class="o">.</span><span class="na">readLine</span><span class="o">());</span>
    <span class="kt">int</span> <span class="n">price</span><span class="o">,</span> <span class="n">count</span><span class="o">,</span> <span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
    
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="o">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">totalCount</span><span class="o">;</span> <span class="n">i</span><span class="o">++){</span>
        <span class="n">st</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StringTokenizer</span><span class="o">(</span><span class="n">br</span><span class="o">.</span><span class="na">readLine</span><span class="o">());</span>
        <span class="n">price</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">();</span>
        <span class="n">count</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">st</span><span class="o">.</span><span class="na">nextToken</span><span class="o">());</span>
        <span class="n">sum</span> <span class="o">+=</span> <span class="o">(</span><span class="n">price</span><span class="o">*</span><span class="n">count</span><span class="o">);</span>
    <span class="o">}</span>
    
    <span class="k">if</span> <span class="o">(</span><span class="n">sum</span> <span class="o">==</span> <span class="n">totalPrice</span><span class="o">){</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Yes"</span><span class="o">);</span>
    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"No"</span><span class="o">);</span>
    <span class="o">}</span>
    
    <span class="c1">// https://www.acmicpc.net/problem/15552</span>
    <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">br</span><span class="o">.</span><span class="na">readLine</span><span class="o">());</span>
    
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">t</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
      <span class="n">st</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StringTokenizer</span><span class="o">(</span><span class="n">br</span><span class="o">.</span><span class="na">readLine</span><span class="o">());</span>
      <span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">st</span><span class="o">.</span><span class="na">nextToken</span><span class="o">());</span>
      <span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">st</span><span class="o">.</span><span class="na">nextToken</span><span class="o">());</span>
      <span class="n">bw</span><span class="o">.</span><span class="na">write</span><span class="o">((</span><span class="n">a</span><span class="o">+</span><span class="n">b</span><span class="o">)</span> <span class="o">+</span> <span class="s">"\n"</span><span class="o">);</span>
    <span class="o">}</span>
    
    <span class="n">bw</span><span class="o">.</span><span class="na">flush</span><span class="o">();</span>
    
    <span class="n">br</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
    <span class="n">bw</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
    
    <span class="c1">// https://www.acmicpc.net/problem/25314</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"byte"</span><span class="o">);</span>
    <span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="n">scan</span><span class="o">.</span><span class="na">nextInt</span><span class="o">();</span>
    
    <span class="k">if</span> <span class="o">(</span><span class="n">size</span> <span class="o">%</span> <span class="mi">4</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
      <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">size</span> <span class="o">/</span> <span class="mi">4</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">print</span><span class="o">(</span><span class="s">"long "</span><span class="o">);</span>
      <span class="o">}</span>
      <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">print</span><span class="o">(</span><span class="s">"int"</span><span class="o">);</span>
    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
      <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"false"</span><span class="o">);</span>
    <span class="o">}</span>
    
    <span class="c1">// https://www.acmicpc.net/problem/11021</span>
    <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">br</span><span class="o">.</span><span class="na">readLine</span><span class="o">());</span>
    
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">t</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
      <span class="n">st</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StringTokenizer</span><span class="o">(</span><span class="n">br</span><span class="o">.</span><span class="na">readLine</span><span class="o">());</span>
      <span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">st</span><span class="o">.</span><span class="na">nextToken</span><span class="o">());</span>
      <span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">st</span><span class="o">.</span><span class="na">nextToken</span><span class="o">());</span>
      <span class="n">bw</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="s">"Case #"</span> <span class="o">+</span> <span class="n">i</span> <span class="o">+</span> <span class="s">": "</span> <span class="o">+</span> <span class="o">(</span><span class="n">a</span><span class="o">+</span><span class="n">b</span><span class="o">)</span> <span class="o">+</span> <span class="s">"\n"</span><span class="o">);</span>
    <span class="o">}</span>
    
    <span class="n">bw</span><span class="o">.</span><span class="na">flush</span><span class="o">();</span>
    
    <span class="n">br</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
    <span class="n">bw</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
    
    <span class="c1">// https://www.acmicpc.net/problem/11022</span>
    <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">br</span><span class="o">.</span><span class="na">readLine</span><span class="o">());</span>

    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">t</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
      <span class="n">st</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StringTokenizer</span><span class="o">(</span><span class="n">br</span><span class="o">.</span><span class="na">readLine</span><span class="o">());</span>
      <span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">st</span><span class="o">.</span><span class="na">nextToken</span><span class="o">());</span>
      <span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">st</span><span class="o">.</span><span class="na">nextToken</span><span class="o">());</span>
      <span class="n">bw</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="s">"Case #"</span> <span class="o">+</span> <span class="n">i</span> <span class="o">+</span> <span class="s">": "</span> <span class="o">+</span> <span class="n">a</span> <span class="o">+</span> <span class="s">" + "</span> <span class="o">+</span> <span class="n">b</span> <span class="o">+</span> <span class="s">" = "</span> <span class="o">+</span> <span class="o">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="o">)</span> <span class="o">+</span> <span class="s">"\n"</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="n">bw</span><span class="o">.</span><span class="na">flush</span><span class="o">();</span>

    <span class="n">br</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
    <span class="n">bw</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
    
    <span class="c1">// https://www.acmicpc.net/problem/2438</span>
    <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="n">scan</span><span class="o">.</span><span class="na">nextInt</span><span class="o">();</span>

    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">t</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
      <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">i</span><span class="o">;</span> <span class="n">j</span><span class="o">++)</span> <span class="o">{</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">print</span><span class="o">(</span><span class="s">"*"</span><span class="o">);</span>
      <span class="o">}</span>
      <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">();</span>
    <span class="o">}</span>
    
    <span class="c1">// https://www.acmicpc.net/problem/2439</span>
    <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="n">scan</span><span class="o">.</span><span class="na">nextInt</span><span class="o">();</span>

    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">t</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
      <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">t</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="n">j</span> <span class="o">&gt;=</span> <span class="n">i</span><span class="o">;</span> <span class="n">j</span><span class="o">--)</span> <span class="o">{</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">print</span><span class="o">(</span><span class="s">" "</span><span class="o">);</span>
      <span class="o">}</span>
      <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">i</span><span class="o">;</span> <span class="n">j</span><span class="o">++)</span> <span class="o">{</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">print</span><span class="o">(</span><span class="s">"*"</span><span class="o">);</span>
      <span class="o">}</span>
      <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">();</span>
    <span class="o">}</span>
    
    <span class="c1">// https://www.acmicpc.net/problem/10952</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">1</span><span class="o">;)</span> <span class="o">{</span>
      <span class="n">st</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StringTokenizer</span><span class="o">(</span><span class="n">br</span><span class="o">.</span><span class="na">readLine</span><span class="o">());</span>
      <span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">st</span><span class="o">.</span><span class="na">nextToken</span><span class="o">());</span>
      <span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">st</span><span class="o">.</span><span class="na">nextToken</span><span class="o">());</span>
      <span class="n">bw</span><span class="o">.</span><span class="na">write</span><span class="o">((</span><span class="n">a</span><span class="o">+</span><span class="n">b</span><span class="o">)</span> <span class="o">+</span> <span class="s">"\n"</span><span class="o">);</span>
      <span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">b</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">break</span><span class="o">;</span>
      <span class="o">}</span>
      <span class="n">i</span><span class="o">--;</span>
    <span class="o">}</span>
    
    <span class="n">bw</span><span class="o">.</span><span class="na">flush</span><span class="o">();</span>
    
    <span class="n">br</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
    <span class="n">bw</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
    
    <span class="c1">// https://www.acmicpc.net/problem/10951</span>
    <span class="k">while</span> <span class="o">(</span><span class="n">scan</span><span class="o">.</span><span class="na">hasNext</span><span class="o">())</span> <span class="o">{</span>
      <span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="n">scan</span><span class="o">.</span><span class="na">nextInt</span><span class="o">();</span>
      <span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="n">scan</span><span class="o">.</span><span class="na">nextInt</span><span class="o">();</span>
      <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">print</span><span class="o">(</span><span class="n">a</span><span class="o">+</span><span class="n">b</span><span class="o">);</span>
    <span class="o">}</span>
    <span class="c1">// EOF - mac: control + d</span>
    
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>]]></content><author><name>gilhanbit</name><email>rlaqnwksp@gmail.com</email></author><category term="Baekjoon" /><category term="baekjoon" /><summary type="html"><![CDATA[for, while 등의 반복문을 사용해 봅시다.]]></summary></entry><entry><title type="html">[Spring] Thymeleaf 기본 사용법</title><link href="https://gilhanbit.github.io/spring/thymeleaf/" rel="alternate" type="text/html" title="[Spring] Thymeleaf 기본 사용법" /><published>2025-05-03T00:00:00+00:00</published><updated>2025-05-03T00:00:00+00:00</updated><id>https://gilhanbit.github.io/spring/spring-thymeleaf</id><content type="html" xml:base="https://gilhanbit.github.io/spring/thymeleaf/"><![CDATA[<h2 id="1-thymeleaf란">1. Thymeleaf란?</h2>

<p>Spring에서 지원하는 html 데이터 렌더링 라이브러리다.</p>

<p>컨트롤러에서 전달된 데이터를 사용하여 동적으로 html 페이지를 구성한다.</p>

<hr />

<h2 id="2-controller">2. Controller</h2>

<p>타임리프를 사용하기 위해서는 컨트롤러 먼저 구성해야 한다.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 컨트롤러 구성 예시</span>

<span class="kn">import</span> <span class="nn">org.springframework.stereotype.Controller</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.web.bind.annotation.GetMapping</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.web.bind.annotation.RequestMapping</span><span class="o">;</span>

<span class="nd">@RequestMapping</span><span class="o">(</span><span class="s">"/thymeleaf"</span><span class="o">)</span>
<span class="nd">@Controller</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Lesson05Controller</span> <span class="o">{</span>

  <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/ex01"</span><span class="o">)</span>
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">ex01</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="s">"thymeleaf/ex01"</span><span class="o">;</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<hr />

<h2 id="3-변수">3. 변수</h2>

<blockquote>
  <p>th:with=”a=1”</p>
</blockquote>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;th:block&gt;이 안에 변수를 선언하면 div와 달리 출력 시 태그가 보이지 않는다.&lt;/th:block&gt; --&gt;</span>

<span class="nt">&lt;h4</span> <span class="na">th:text=</span><span class="s">"'&lt;b&gt;bold&lt;/b&gt;'"</span><span class="nt">&gt;&lt;/h4&gt;</span> <span class="c">&lt;!-- 출력: &lt;b&gt;bold&lt;/b&gt; --&gt;</span>
<span class="nt">&lt;h4</span> <span class="na">th:utext=</span><span class="s">"'&lt;b&gt;bold&lt;/b&gt;'"</span><span class="nt">&gt;&lt;/h4&gt;</span> <span class="c">&lt;!-- 출력: bold --&gt;</span>

<span class="nt">&lt;div</span> <span class="na">th:with=</span><span class="s">"number=100"</span><span class="nt">&gt;</span> <span class="c">&lt;!-- 100을 number에 담는다. --&gt;</span>
  <span class="nt">&lt;h4</span> <span class="na">th:text=</span><span class="s">"${number}"</span><span class="nt">&gt;&lt;/h4&gt;</span> <span class="c">&lt;!-- 변수값 출력 (정석) --&gt;</span>
  <span class="nt">&lt;h4&gt;</span>[[${number}]]<span class="nt">&lt;/h4&gt;</span> <span class="c">&lt;!-- 간소화 --&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<p>주의해야할 점은 <strong><font color="#990000">변수 태그 스코프 내에 있어야</font></strong> 변수 사용이 가능하다.</p>

<hr />

<h2 id="4-산술연산">4. 산술연산</h2>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">th:with=</span><span class="s">"number1=100, number2=30"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;h4</span> <span class="na">th:text=</span><span class="s">"'sum:' + ${number1 + number2}"</span><span class="nt">&gt;&lt;/h4&gt;</span> <span class="c">&lt;!-- 텍스트와 함께 사용 시 텍스트를 ''로 묶는다. --&gt;</span>
  <span class="nt">&lt;h4&gt;</span>sum: [[${number1 + number2}]]<span class="nt">&lt;/h4&gt;</span> <span class="c">&lt;!-- ''로 묶지 않고 텍스트 출력하는 방법 --&gt;</span>
  <span class="nt">&lt;h4</span> <span class="na">th:text=</span><span class="s">"|sum: ${number1 + number2}|"</span><span class="nt">&gt;&lt;/h4&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<hr />

<h2 id="5-조건문">5. 조건문</h2>

<blockquote>
  <p>th:if / th:unless<br />
th:switch / th:case</p>
</blockquote>

<p>타임리프에는 else if, else와 같은 개념이 없다.</p>

<p>타임리프에서 <code class="language-plaintext highlighter-rouge">if</code> / <code class="language-plaintext highlighter-rouge">unless</code>는 태그를 나타낼지, 나타내지 않을지의 조건, <code class="language-plaintext highlighter-rouge">switch</code> / <code class="language-plaintext highlighter-rouge">case</code>는 일치되는 태그를 수행한다.</p>

<h3 id="5-1-if--unless">5-1. if / unless</h3>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- if, unless --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">th:with=</span><span class="s">"age=30"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;h4</span> <span class="na">th:if=</span><span class="s">"${age &gt;= 20}"</span><span class="nt">&gt;</span>성인<span class="nt">&lt;/h4&gt;</span>
  <span class="nt">&lt;h4</span> <span class="na">th:unless=</span><span class="s">"${age &gt;= 20}"</span><span class="nt">&gt;</span>미성년자<span class="nt">&lt;/h4&gt;</span>
  <span class="c">&lt;!--
  unless는 거짓일 때 출력된다.
  age &gt;= 20의 조건은 '참이므로 성인이 출력'되며 미성년자는 출력되지 않는다.
  반대로 조건이 age &lt;= 20일 경우 '거짓이므로 미성년자가 출력'된다.
   --&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<h3 id="5-2-switch--case">5-2. switch / case</h3>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- switch, case --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">th:with=</span><span class="s">"season=summer"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">th:switch=</span><span class="s">"${season}"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;h4</span> <span class="na">th:case=</span><span class="s">"spring"</span><span class="nt">&gt;</span>spring<span class="nt">&lt;/h4&gt;</span>
    <span class="nt">&lt;h4</span> <span class="na">th:case=</span><span class="s">"summer"</span><span class="nt">&gt;</span>summer<span class="nt">&lt;/h4&gt;</span>
    <span class="nt">&lt;h4</span> <span class="na">th:case=</span><span class="s">"autumn"</span><span class="nt">&gt;</span>autumn<span class="nt">&lt;/h4&gt;</span>
    <span class="nt">&lt;h4</span> <span class="na">th:case=</span><span class="s">"*"</span><span class="nt">&gt;</span>winter<span class="nt">&lt;/h4&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="c">&lt;!--
출력: summer

어디에도 해당되지 않을 경우, 마지막 default 값인 winter 출력.
--&gt;</span>
</code></pre></div></div>

<hr />

<h2 id="6-반복문">6. 반복문</h2>

<blockquote>
  <p>th:each=”a : ${b}”</p>
</blockquote>

<p>b를 a에 담아 반복한다. (중첩 반복문과 동일)</p>

<h3 id="6-1-숫자">6-1. 숫자</h3>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- 숫자 반복 --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">th:each=</span><span class="s">"value:${#numbers.sequence(0, 5)}"</span><span class="nt">&gt;</span>
[[${value}]]
<span class="nt">&lt;/div&gt;</span>

<span class="c">&lt;!--
출력
0
1
2
3
4
5
--&gt;</span>


<span class="c">&lt;!-- status 추가 (두 번째 변수 명에 상태 저장) --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">th:each=</span><span class="s">"value, status:${#numbers.sequence(16, 20)}"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">th:text=</span><span class="s">"${value}"</span><span class="nt">&gt;&lt;/span&gt;</span>
  status: <span class="nt">&lt;span</span> <span class="na">th:text=</span><span class="s">"${status}"</span><span class="nt">&gt;&lt;/span&gt;</span>
  count: <span class="nt">&lt;span</span> <span class="na">th:text=</span><span class="s">"${status.count}"</span><span class="nt">&gt;&lt;/span&gt;</span>
  index: <span class="nt">&lt;span</span> <span class="na">th:text=</span><span class="s">"${status.index}"</span><span class="nt">&gt;&lt;/span&gt;</span>
  first: <span class="nt">&lt;span</span> <span class="na">th:text=</span><span class="s">"${status.first}"</span><span class="nt">&gt;&lt;/span&gt;</span>
  last: <span class="nt">&lt;span</span> <span class="na">th:text=</span><span class="s">"${status.last}"</span><span class="nt">&gt;&lt;/span&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<p><img src="/assets/images/posts_img/spring/thymeleaf/status.png" alt="status" /></p>

<blockquote>
  <p>status</p>
</blockquote>

<ul>
  <li>index: 0부터 출력</li>
  <li>count: 1부터 출력</li>
  <li>first: 반복문이 첫번째로 돌았다면 true</li>
  <li>last: 반복문이 마지막일 경우 true</li>
  <li>current: 현재 변수 값 출력</li>
</ul>

<p>위 메서드 외에도 <a href="https://www.thymeleaf.org/apidocs/thymeleaf/3.0.0.BETA02/org/thymeleaf/engine/IterationStatusVar.html#getCount--">IterationStatusVar</a>에 들어가면 다양한 메서드들을 확인할 수 있다.</p>

<h3 id="6-2-list">6-2. List</h3>

<p>특정 값을 반복하려면 controller에 먼저 Model 객체가 있어야 한다.</p>

<p><strong>이를 응용해 DB 데이터를 반복해 출력할 수 있다.</strong></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// controller</span>
<span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/ex02"</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">ex02</span><span class="o">(</span><span class="nc">Model</span> <span class="n">model</span><span class="o">)</span> <span class="o">{</span>
  <span class="c1">// 1</span>
  <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">fruits</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;(</span><span class="nc">Arrays</span><span class="o">.</span><span class="na">asList</span><span class="o">(</span><span class="s">"apple"</span><span class="o">,</span> <span class="s">"melon"</span><span class="o">,</span> <span class="s">"peach"</span><span class="o">,</span> <span class="s">"grape"</span><span class="o">,</span> <span class="s">"mango"</span><span class="o">));</span>
  <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"fruits"</span><span class="o">,</span> <span class="n">fruits</span><span class="o">);</span>
  

  <span class="c1">// 2</span>
  <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Map</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Object</span><span class="o">&gt;&gt;</span> <span class="n">users</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
  <span class="nc">Map</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Object</span><span class="o">&gt;</span> <span class="n">user</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">&lt;&gt;();</span>
  <span class="n">user</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"name"</span><span class="o">,</span> <span class="s">"tom"</span><span class="o">);</span>
  <span class="n">user</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"age"</span><span class="o">,</span> <span class="mi">30</span><span class="o">);</span>
  <span class="n">user</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"hobby"</span><span class="o">,</span> <span class="s">"run"</span><span class="o">);</span>
  <span class="n">users</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">user</span><span class="o">);</span>
  
  <span class="n">user</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">&lt;&gt;();</span>
  <span class="n">user</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"name"</span><span class="o">,</span> <span class="s">"brown"</span><span class="o">);</span>
  <span class="n">user</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"age"</span><span class="o">,</span> <span class="mi">20</span><span class="o">);</span>
  <span class="n">user</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"hobby"</span><span class="o">,</span> <span class="s">"eat"</span><span class="o">);</span>
  <span class="n">users</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">user</span><span class="o">);</span>
  
  <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"users"</span><span class="o">,</span> <span class="n">users</span><span class="o">);</span>
  
  <span class="k">return</span> <span class="s">"lesson05/ex02"</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- List 반복문 - String --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">th:each=</span><span class="s">"fruit, status:${fruits}"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">th:text=</span><span class="s">"${fruit}"</span><span class="nt">&gt;&lt;/span&gt;</span>
  count: <span class="nt">&lt;span</span> <span class="na">th:text=</span><span class="s">"${status.count}"</span><span class="nt">&gt;&lt;/span&gt;</span>
  index: <span class="nt">&lt;span</span> <span class="na">th:text=</span><span class="s">"${status.index}"</span><span class="nt">&gt;&lt;/span&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;hr&gt;</span>

<span class="c">&lt;!--
출력
apple count: 1 index: 0
melon count: 2 index: 1
peach count: 3 index: 2
grape count: 4 index: 3
mango count: 5 index: 4
--&gt;</span>


<span class="c">&lt;!-- Map --&gt;</span>
<span class="nt">&lt;table</span> <span class="na">class=</span><span class="s">"table"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;thead&gt;</span>
    <span class="nt">&lt;tr&gt;</span>
      <span class="nt">&lt;th&gt;</span>no<span class="nt">&lt;/th&gt;</span>
      <span class="nt">&lt;th&gt;</span>name<span class="nt">&lt;/th&gt;</span>
      <span class="nt">&lt;th&gt;</span>age<span class="nt">&lt;/th&gt;</span>
      <span class="nt">&lt;th&gt;</span>hobby<span class="nt">&lt;/th&gt;</span>
    <span class="nt">&lt;/tr&gt;</span>
  <span class="nt">&lt;/thead&gt;</span>
  <span class="nt">&lt;tbody&gt;</span>
    <span class="nt">&lt;tr</span> <span class="na">th:each=</span><span class="s">"user, status:${users}"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${status.count}"</span><span class="nt">&gt;&lt;/td&gt;</span>
      <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${user.name}"</span><span class="nt">&gt;&lt;/td&gt;</span>
      <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${user.age}"</span><span class="nt">&gt;&lt;/td&gt;</span>
      <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${user.hobby}"</span><span class="nt">&gt;&lt;/td&gt;</span>
    <span class="nt">&lt;/tr&gt;</span>
  <span class="nt">&lt;/tbody&gt;</span>
<span class="nt">&lt;/table&gt;</span>
</code></pre></div></div>]]></content><author><name>gilhanbit</name><email>rlaqnwksp@gmail.com</email></author><category term="Spring" /><category term="spring" /><category term="mvc" /><category term="thymeleaf" /><summary type="html"><![CDATA[변수, 산술연산, 조건문, 반복문]]></summary></entry></feed>