<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>메밀이의 공부일기</title>
    <link>https://buckwheat0.tistory.com/</link>
    <description>buckwheat 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Sat, 18 Jul 2026 17:09:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>buckwheat</managingEditor>
    <item>
      <title>[26.07.06-26.07.09] TIL 15주차 정리</title>
      <link>https://buckwheat0.tistory.com/80</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/76&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://buckwheat0.tistory.com/76&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1783919408546&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[2026.07.06] - TIL 66일차 (Spring Boot 게시판 보완과 Thymeleaf 시작)&quot; data-og-description=&quot;기존 StartBoot02 게시판 프로젝트를 보완하고, StartBoot03에서 Thymeleaf 기본 문법을 학습했다.기존 JSP 기반 흐름에서 Spring Boot 방식의 설정, 필터, 인터셉터, MyBatis Mapper 구조를 조금 더 정리했고, 이후&quot; data-og-host=&quot;buckwheat0.tistory.com&quot; data-og-source-url=&quot;https://buckwheat0.tistory.com/76&quot; data-og-url=&quot;https://buckwheat0.tistory.com/76&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/h8oqB/dJMb8VNHWDn/6EGlUqj8uKr9T91Ym76UpK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/belEIF/dJMb8Z3DGUP/HwKkJXsOZjlTOufhsltAok/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/druePq/dJMb8Z3DGUO/zWC4EfVLNIDbkdFq2QR36K/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/76&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://buckwheat0.tistory.com/76&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/h8oqB/dJMb8VNHWDn/6EGlUqj8uKr9T91Ym76UpK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/belEIF/dJMb8Z3DGUP/HwKkJXsOZjlTOufhsltAok/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/druePq/dJMb8Z3DGUO/zWC4EfVLNIDbkdFq2QR36K/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[2026.07.06] - TIL 66일차 (Spring Boot 게시판 보완과 Thymeleaf 시작)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;기존 StartBoot02 게시판 프로젝트를 보완하고, StartBoot03에서 Thymeleaf 기본 문법을 학습했다.기존 JSP 기반 흐름에서 Spring Boot 방식의 설정, 필터, 인터셉터, MyBatis Mapper 구조를 조금 더 정리했고, 이후&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;buckwheat0.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/77&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://buckwheat0.tistory.com/77&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1783919418907&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[2026.07.07] - TIL 67일차 (JSP 게시판을 Thymeleaf로 전환하기)&quot; data-og-description=&quot;StartBoot02_Thymeleaf 프로젝트에서 기존 JSP 게시판 화면을 Thymeleaf 템플릿으로 바꾸는 작업을 했다.기존 Controller, Biz, Dao, Mapper 구조는 유지하고, View 영역만 JSP에서 Thymeleaf HTML로 전환하는 흐름이었다&quot; data-og-host=&quot;buckwheat0.tistory.com&quot; data-og-source-url=&quot;https://buckwheat0.tistory.com/77&quot; data-og-url=&quot;https://buckwheat0.tistory.com/77&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/y0sgn/dJMb9b334yl/ONKlSUwDfqFHdP3TlpEt51/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/Qkld1/dJMb896fTK2/uCfiySQjaJpbDqGKEFq99K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cJ33Lj/dJMb9jgJsK1/OYIhO8yzBSpF12ipz9mvSk/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/77&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://buckwheat0.tistory.com/77&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/y0sgn/dJMb9b334yl/ONKlSUwDfqFHdP3TlpEt51/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/Qkld1/dJMb896fTK2/uCfiySQjaJpbDqGKEFq99K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cJ33Lj/dJMb9jgJsK1/OYIhO8yzBSpF12ipz9mvSk/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[2026.07.07] - TIL 67일차 (JSP 게시판을 Thymeleaf로 전환하기)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;StartBoot02_Thymeleaf 프로젝트에서 기존 JSP 게시판 화면을 Thymeleaf 템플릿으로 바꾸는 작업을 했다.기존 Controller, Biz, Dao, Mapper 구조는 유지하고, View 영역만 JSP에서 Thymeleaf HTML로 전환하는 흐름이었다&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;buckwheat0.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/78&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://buckwheat0.tistory.com/78&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1783919434723&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[2026.07.08] - TIL 68일차 (Spring Data JPA로 게시판 CRUD 구현하기)&quot; data-og-description=&quot;오늘은 StartBoot04 프로젝트에서 Spring Data JPA를 사용해 기존 게시판 흐름을 다시 구현했다.이전에는 MyBatis Mapper에 SQL을 직접 작성했다면, 오늘은 Entity와 Repository를 중심으로 DB 작업을 처리했다.1. J&quot; data-og-host=&quot;buckwheat0.tistory.com&quot; data-og-source-url=&quot;https://buckwheat0.tistory.com/78&quot; data-og-url=&quot;https://buckwheat0.tistory.com/78&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bR9aze/dJMb86n9N4i/MtukEFK0TLpb0iaB8hlKG1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b34TD2/dJMb9lMnvX8/ecAppk6bKLkSfcpVzoFXBk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/BwFjw/dJMb9fZHoPK/VGbuzdc1TK2mDzndZNSzB0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/78&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://buckwheat0.tistory.com/78&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bR9aze/dJMb86n9N4i/MtukEFK0TLpb0iaB8hlKG1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b34TD2/dJMb9lMnvX8/ecAppk6bKLkSfcpVzoFXBk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/BwFjw/dJMb9fZHoPK/VGbuzdc1TK2mDzndZNSzB0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[2026.07.08] - TIL 68일차 (Spring Data JPA로 게시판 CRUD 구현하기)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 StartBoot04 프로젝트에서 Spring Data JPA를 사용해 기존 게시판 흐름을 다시 구현했다.이전에는 MyBatis Mapper에 SQL을 직접 작성했다면, 오늘은 Entity와 Repository를 중심으로 DB 작업을 처리했다.1. J&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;buckwheat0.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/79&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://buckwheat0.tistory.com/79&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1783919443011&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[2026.07.09] - TIL 69일차 (Spring Security와 로그인 구현)&quot; data-og-description=&quot;1. Spring Security 의존성 추가Spring Boot 프로젝트에 로그인과 접근 권한 기능을 적용하기 위해 Spring Security 의존성을 추가했다. org.springframework.boot spring-boot-starter-security org.thymeleaf.extras thymeleaf-extras-s&quot; data-og-host=&quot;buckwheat0.tistory.com&quot; data-og-source-url=&quot;https://buckwheat0.tistory.com/79&quot; data-og-url=&quot;https://buckwheat0.tistory.com/79&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/wyJUg/dJMb887kVEG/96NYYvibu2v62wLblmUPvK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bZiXds/dJMb84YaUjK/lsnXkjtTmCSozLpck43D2K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/tIt4i/dJMb86PdVMP/mK1Odrw8egkpZIeEKkFrdK/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/79&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://buckwheat0.tistory.com/79&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/wyJUg/dJMb887kVEG/96NYYvibu2v62wLblmUPvK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bZiXds/dJMb84YaUjK/lsnXkjtTmCSozLpck43D2K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/tIt4i/dJMb86PdVMP/mK1Odrw8egkpZIeEKkFrdK/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[2026.07.09] - TIL 69일차 (Spring Security와 로그인 구현)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1. Spring Security 의존성 추가Spring Boot 프로젝트에 로그인과 접근 권한 기능을 적용하기 위해 Spring Security 의존성을 추가했다. org.springframework.boot spring-boot-starter-security org.thymeleaf.extras thymeleaf-extras-s&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;buckwheat0.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>멀티캠퍼스/주차별 정리</category>
      <category>[현대이지웰] Java 풀스택 개발자 아카데미 8회차</category>
      <category>멀티캠퍼스 부트캠프</category>
      <category>부트캠프</category>
      <author>buckwheat</author>
      <guid isPermaLink="true">https://buckwheat0.tistory.com/80</guid>
      <comments>https://buckwheat0.tistory.com/80#entry80comment</comments>
      <pubDate>Mon, 13 Jul 2026 14:10:51 +0900</pubDate>
    </item>
    <item>
      <title>[2026.07.09] - TIL 69일차 (Spring Security와 로그인 구현)</title>
      <link>https://buckwheat0.tistory.com/79</link>
      <description>&lt;h2&gt;1. Spring Security 의존성 추가&lt;/h2&gt;
&lt;p&gt;Spring Boot 프로젝트에 로그인과 접근 권한 기능을 적용하기 위해 Spring Security 의존성을 추가했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-security&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;

&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.thymeleaf.extras&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;thymeleaf-extras-springsecurity5&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;spring-boot-starter-security&lt;/code&gt;는 인증과 권한 처리를 담당한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;thymeleaf-extras-springsecurity5&lt;/code&gt;는 Thymeleaf 화면에서 로그인 정보와 권한을 사용할 수 있게 해준다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. 게시판 Entity와 JPA&lt;/h2&gt;
&lt;p&gt;게시글 정보를 저장하기 위해 &lt;code&gt;BoardEntity&lt;/code&gt;를 작성했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Entity
@Table(name = &amp;quot;board&amp;quot;)
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class BoardEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(nullable = false, length = 50)
    private String write;

    @Column(nullable = false, length = 100)
    private String title;

    @Column(length = 4000)
    private String content;

    @Column(updatable = false)
    private LocalDate createAt;

    @PrePersist
    public void onPrePersist() {
        this.createAt = LocalDate.now();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@Entity&lt;/code&gt;: JPA가 관리하는 Entity로 등록&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Table&lt;/code&gt;: 연결할 테이블 이름 지정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Id&lt;/code&gt;: 기본키 지정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@GeneratedValue&lt;/code&gt;: 기본키 자동 생성&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@PrePersist&lt;/code&gt;: INSERT 직전에 실행&lt;/li&gt;
&lt;li&gt;Lombok: 생성자와 getter, setter 코드 자동 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;3. Repository와 Service&lt;/h2&gt;
&lt;p&gt;Repository는 &lt;code&gt;JpaRepository&lt;/code&gt;를 상속받아 기본 CRUD 기능을 사용한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public interface BoardRepository
        extends JpaRepository&amp;lt;BoardEntity, Integer&amp;gt; {

    List&amp;lt;BoardEntity&amp;gt; findAllByOrderByIdDesc();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;메서드 이름을 분석해 게시글을 ID 내림차순으로 조회하는 SQL을 자동 생성한다.&lt;/p&gt;
&lt;p&gt;Service에서는 Repository를 이용해 게시글 조회와 저장을 처리했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Override
public List&amp;lt;BoardEntity&amp;gt; findAll() {
    return repository.findAllByOrderByIdDesc();
}

@Override
public BoardEntity save(BoardEntity dto) {
    return repository.save(dto);
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;4. 게시글 목록, 등록, 상세 조회&lt;/h2&gt;
&lt;p&gt;Controller에서 게시글 목록, 등록 화면, 저장, 상세 조회 요청을 처리했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@GetMapping(&amp;quot;/list&amp;quot;)
public String selectList(Model model) {
    model.addAttribute(&amp;quot;list&amp;quot;, service.findAll());
    return &amp;quot;board/list&amp;quot;;
}

@GetMapping(&amp;quot;/insert&amp;quot;)
public String insertForm() {
    return &amp;quot;board/insert&amp;quot;;
}

@PostMapping(&amp;quot;/insert&amp;quot;)
public String insert(BoardEntity dto) {
    service.save(dto);
    return &amp;quot;redirect:/board/list&amp;quot;;
}

@GetMapping(&amp;quot;/detail&amp;quot;)
public String selectOne(Model model, int id) {
    model.addAttribute(&amp;quot;dto&amp;quot;, service.findById(id));
    return &amp;quot;board/detail&amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@GetMapping&lt;/code&gt;: 화면 조회 요청&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@PostMapping&lt;/code&gt;: 입력 데이터를 서버에 전달하는 요청&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Model&lt;/code&gt;: Controller에서 조회한 데이터를 Thymeleaf로 전달&lt;/li&gt;
&lt;li&gt;&lt;code&gt;redirect:&lt;/code&gt;: 작업 완료 후 새로운 주소로 다시 요청&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;5. 회원 Entity와 회원가입&lt;/h2&gt;
&lt;p&gt;회원 정보를 저장하기 위해 &lt;code&gt;MemberEntity&lt;/code&gt;를 작성했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Entity
@Table(name = &amp;quot;member&amp;quot;)
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class MemberEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(nullable = false, length = 50, unique = true)
    private String username;

    @Column(nullable = false, length = 100)
    private String password;

    @Column(nullable = false, length = 50)
    private String name;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;username&lt;/code&gt;에는 &lt;code&gt;unique = true&lt;/code&gt;를 지정해 같은 아이디가 중복 저장되지 않도록 했다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;6. BCrypt 비밀번호 암호화&lt;/h2&gt;
&lt;p&gt;비밀번호를 평문으로 저장하지 않도록 &lt;code&gt;BCryptPasswordEncoder&lt;/code&gt;를 Bean으로 등록했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;회원가입 시 입력받은 비밀번호를 암호화한 뒤 DB에 저장한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Override
public MemberEntity save(MemberEntity dto) {
    dto.setPassword(passwordEncoder.encode(dto.getPassword()));
    return repository.save(dto);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;BCrypt로 암호화된 비밀번호는 약 60자의 문자열로 저장된다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;7. UserDetailsService&lt;/h2&gt;
&lt;p&gt;Spring Security는 로그인 요청이 들어오면 &lt;code&gt;loadUserByUsername()&lt;/code&gt;을 호출해 사용자를 조회한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Override
public UserDetails loadUserByUsername(String username)
        throws UsernameNotFoundException {

    MemberEntity member = repository.findByUsername(username)
        .orElseThrow(() -&amp;gt;
            new UsernameNotFoundException(&amp;quot;사용자를 찾을 수 없습니다.&amp;quot;));

    return User.builder()
        .username(member.getUsername())
        .password(member.getPassword())
        .roles(&amp;quot;USER&amp;quot;)
        .build();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DB에서 조회한 &lt;code&gt;MemberEntity&lt;/code&gt;를 Spring Security가 사용하는 &lt;code&gt;UserDetails&lt;/code&gt; 형태로 변환한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;8. SecurityFilterChain&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;SecurityFilterChain&lt;/code&gt;에서 URL별 접근 권한과 로그인 방식을 설정했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Bean
public SecurityFilterChain filterChain(HttpSecurity http)
        throws Exception {

    http.csrf(csrf -&amp;gt; csrf.disable())
        .authorizeHttpRequests(auth -&amp;gt; auth
            .antMatchers(
                &amp;quot;/&amp;quot;,
                &amp;quot;/member/register&amp;quot;,
                &amp;quot;/member/login&amp;quot;,
                &amp;quot;/css/**&amp;quot;,
                &amp;quot;/js/**&amp;quot;,
                &amp;quot;/images/**&amp;quot;
            ).permitAll()
            .antMatchers(&amp;quot;/board/**&amp;quot;).authenticated()
            .anyRequest().permitAll())
        .formLogin(form -&amp;gt; form
            .loginPage(&amp;quot;/member/login&amp;quot;)
            .loginProcessingUrl(&amp;quot;/member/login&amp;quot;)
            .defaultSuccessUrl(&amp;quot;/board/list&amp;quot;, true)
            .failureUrl(&amp;quot;/member/login?error=true&amp;quot;)
            .permitAll())
        .logout(logout -&amp;gt; logout
            .logoutUrl(&amp;quot;/member/logout&amp;quot;)
            .logoutSuccessUrl(&amp;quot;/&amp;quot;)
            .permitAll());

    return http.build();
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;permitAll()&lt;/code&gt;: 로그인하지 않아도 접근 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;authenticated()&lt;/code&gt;: 로그인한 사용자만 접근 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;loginPage()&lt;/code&gt;: 로그인 화면 주소&lt;/li&gt;
&lt;li&gt;&lt;code&gt;loginProcessingUrl()&lt;/code&gt;: Spring Security가 처리할 로그인 요청 주소&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defaultSuccessUrl()&lt;/code&gt;: 로그인 성공 후 이동할 주소&lt;/li&gt;
&lt;li&gt;&lt;code&gt;failureUrl()&lt;/code&gt;: 로그인 실패 후 이동할 주소&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;9. 로그인 처리 흐름&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;로그인 폼 제출
→ Spring Security Filter
→ loadUserByUsername() 호출
→ DB에서 회원 조회
→ BCrypt 비밀번호 비교
→ 인증 성공
→ /board/list 이동&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Spring Security가 &lt;code&gt;POST /member/login&lt;/code&gt; 요청을 처리하기 때문에 Controller에서 아이디와 비밀번호를 직접 비교하지 않아도 된다.&lt;/p&gt;
&lt;p&gt;Controller는 로그인 화면을 반환하는 GET 요청만 처리한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@GetMapping(&amp;quot;/login&amp;quot;)
public String loginForm() {
    return &amp;quot;member/login&amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;10. ddl-auto 설정&lt;/h2&gt;
&lt;p&gt;수업에서는 서버 실행 시 테이블을 새로 생성하기 위해 다음 설정을 사용했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-properties&quot;&gt;spring.jpa.hibernate.ddl-auto=create&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;create&lt;/code&gt;는 서버를 실행할 때 기존 테이블을 삭제하고 다시 생성한다. 이 때문에 서버를 재시작하면 회원과 게시글 데이터가 사라질 수 있다.&lt;/p&gt;
&lt;p&gt;실습 중 데이터를 유지하기 위해 다음과 같이 변경했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-properties&quot;&gt;spring.jpa.hibernate.ddl-auto=update&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;update&lt;/code&gt;는 기존 데이터를 유지하면서 Entity 변경 사항을 테이블에 반영한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;정리&lt;/h2&gt;
&lt;p&gt;오늘은 Spring Data JPA로 게시판과 회원 테이블을 구성하고, Spring Security를 이용해 회원가입과 로그인 기능을 구현했다.&lt;/p&gt;
&lt;p&gt;비밀번호는 BCrypt로 암호화했으며, &lt;code&gt;UserDetailsService&lt;/code&gt;로 DB 회원을 조회했다. 또한 로그인하지 않은 사용자는 &lt;code&gt;/board/**&lt;/code&gt;에 접근할 수 없도록 URL 권한을 설정했다.&lt;/p&gt;</description>
      <category>멀티캠퍼스</category>
      <category>[현대이지웰] Java 풀스택 개발자 아카데미 8회차</category>
      <category>멀티캠퍼스부트캠프</category>
      <category>부트캠프</category>
      <author>buckwheat</author>
      <guid isPermaLink="true">https://buckwheat0.tistory.com/79</guid>
      <comments>https://buckwheat0.tistory.com/79#entry79comment</comments>
      <pubDate>Thu, 9 Jul 2026 17:58:42 +0900</pubDate>
    </item>
    <item>
      <title>[2026.07.08] - TIL 68일차 (Spring Data JPA로 게시판 CRUD 구현하기)</title>
      <link>https://buckwheat0.tistory.com/78</link>
      <description>&lt;p&gt;오늘은 &lt;code&gt;StartBoot04&lt;/code&gt; 프로젝트에서 Spring Data JPA를 사용해 기존 게시판 흐름을 다시 구현했다.&lt;br&gt;이전에는 MyBatis Mapper에 SQL을 직접 작성했다면, 오늘은 Entity와 Repository를 중심으로 DB 작업을 처리했다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;1. JPA 프로젝트 설정&lt;/h1&gt;
&lt;p&gt;JPA를 사용하려면 DB 연결 정보와 Hibernate 설정이 필요하다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-properties&quot;&gt;spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521/XEPDB1
spring.datasource.username=multi
spring.datasource.password=multi

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle12cDialect
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ddl-auto=validate&lt;/code&gt;는 Entity와 DB 테이블 구조가 맞는지 검사한다.&lt;br&gt;테이블이나 시퀀스가 맞지 않으면 서버 시작 단계에서 에러가 난다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;2. Entity 클래스&lt;/h1&gt;
&lt;p&gt;JPA에서는 DB 테이블과 연결되는 Java 객체를 Entity라고 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Entity
@Table(name=&amp;quot;MYBOARD&amp;quot;)
public class JpaEntity {

    @Id
    @SequenceGenerator(name=&amp;quot;my_seq&amp;quot;, sequenceName=&amp;quot;SEQ_MY&amp;quot;, allocationSize=1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator=&amp;quot;my_seq&amp;quot;)
    @Column
    private int myno;

    @Column(updatable=false, nullable=false)
    private String myname;

    @Column
    private String mytitle;

    @Column
    private String mycontent;

    @Column(updatable=false, nullable=false)
    private Date mydate;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;핵심은 &lt;code&gt;@Entity&lt;/code&gt;, &lt;code&gt;@Table&lt;/code&gt;, &lt;code&gt;@Id&lt;/code&gt;다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;@Entity
- 이 클래스가 JPA가 관리하는 DB 객체라는 뜻

@Table
- 실제 DB 테이블 이름 지정

@Id
- 기본키 필드 지정&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기존 DB에서는 &lt;code&gt;SEQ_MY&lt;/code&gt; 시퀀스를 사용하고 있었기 때문에 &lt;code&gt;@SequenceGenerator&lt;/code&gt;로 JPA가 이 시퀀스를 사용하게 설정했다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;3. Repository와 JpaRepository&lt;/h1&gt;
&lt;p&gt;JPA에서는 DAO 역할을 Repository 인터페이스로 만들 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Repository
public interface JpaDao extends JpaRepository&amp;lt;JpaEntity, Integer&amp;gt; {

    public JpaEntity findByMyno(int myno);

    //JPQL
    @Query(&amp;quot;DELETE FROM JpaEntity J WHERE J.myno = :myno&amp;quot;)
    @Modifying
    @Transactional
    public void delBoard(@Param(&amp;quot;myno&amp;quot;) int myno);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;JpaRepository&amp;lt;JpaEntity, Integer&amp;gt;&lt;/code&gt;는 이렇게 해석할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;JpaEntity : 이 Repository가 관리할 Entity
Integer   : Entity의 기본키 타입&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;JpaRepository&lt;/code&gt;를 상속하면 기본 CRUD 메서드를 바로 사용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;dao.findAll();
dao.save(dto);
dao.deleteById(myno);&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;4. findBy 메서드 규칙&lt;/h1&gt;
&lt;p&gt;Spring Data JPA는 메서드 이름을 보고 쿼리를 자동으로 만들어준다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public JpaEntity findByMyno(int myno);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 코드는 &lt;code&gt;myno&lt;/code&gt; 필드로 데이터를 조회한다는 뜻이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;findBy필드명
= 해당 필드 조건으로 조회&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;중요한 점은 DB 컬럼명이 아니라 &lt;strong&gt;Entity 필드명&lt;/strong&gt;을 기준으로 작성한다는 것이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;5. JPQL에서 주의할 점&lt;/h1&gt;
&lt;p&gt;JPQL은 SQL과 비슷해 보이지만 기준이 다르다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Query(&amp;quot;DELETE FROM JpaEntity J WHERE J.myno = :myno&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SQL이라면 테이블명과 컬럼명을 사용한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;DELETE FROM MYBOARD WHERE MYNO = ?&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;하지만 JPQL은 Entity명과 필드명을 사용한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;MYBOARD X  -&amp;gt; JpaEntity O
MYNO    X  -&amp;gt; myno O&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그래서 &lt;code&gt;J.MYNO&lt;/code&gt;처럼 쓰면 에러가 난다.&lt;br&gt;&lt;code&gt;JpaEntity&lt;/code&gt; 클래스 안에는 &lt;code&gt;MYNO&lt;/code&gt;가 아니라 &lt;code&gt;myno&lt;/code&gt; 필드가 있기 때문이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;6. Controller CRUD 흐름&lt;/h1&gt;
&lt;p&gt;목록 조회는 &lt;code&gt;findAll()&lt;/code&gt;을 사용했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@GetMapping(&amp;quot;/list&amp;quot;)
public String selectAll(Model model) {
    List&amp;lt;JpaEntity&amp;gt; list = dao.findAll(Sort.by(Sort.Direction.DESC, &amp;quot;myno&amp;quot;));
    model.addAttribute(&amp;quot;list&amp;quot;, list);
    return &amp;quot;jpalist&amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;상세 조회는 &lt;code&gt;findByMyno()&lt;/code&gt;를 사용했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@GetMapping(&amp;quot;/detail&amp;quot;)
public String selectOne(Model model, int myno) {
    JpaEntity dto = dao.findByMyno(myno);
    model.addAttribute(&amp;quot;dto&amp;quot;, dto);
    return &amp;quot;jpadetail&amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;등록은 &lt;code&gt;save()&lt;/code&gt;를 사용했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@PostMapping(&amp;quot;/insert&amp;quot;)
public String insert(JpaEntity dto) {
    dto.setMydate(new Date(System.currentTimeMillis()));
    dao.save(dto);
    return &amp;quot;redirect:/board/list&amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;mydate&lt;/code&gt;는 form에서 입력받지 않기 때문에 Controller에서 직접 현재 날짜를 넣어주었다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;7. save()의 insert/update 판단&lt;/h1&gt;
&lt;p&gt;JPA의 &lt;code&gt;save()&lt;/code&gt;는 insert와 update를 모두 처리할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;dao.save(dto);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기준은 기본키다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;id가 없거나 DB에 없는 값이면 insert
id가 있고 DB에 같은 데이터가 있으면 update&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;수정에서는 기존 데이터를 다시 조회한 뒤 제목과 내용만 바꿔 저장했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@PostMapping(&amp;quot;/update&amp;quot;)
public String update(JpaEntity dto) {
    JpaEntity Dto = dao.findByMyno(dto.getMyno());
    Dto.setMytitle(dto.getMytitle());
    Dto.setMycontent(dto.getMycontent());
    dao.save(Dto);

    return &amp;quot;redirect:/board/detail?myno=&amp;quot; + dto.getMyno();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 하면 form에서 넘어오지 않은 &lt;code&gt;myname&lt;/code&gt;, &lt;code&gt;mydate&lt;/code&gt; 값이 유지된다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;8. Thymeleaf 화면 처리&lt;/h1&gt;
&lt;p&gt;목록 화면에서는 &lt;code&gt;th:each&lt;/code&gt;로 데이터를 반복 출력했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;tr th:each=&amp;quot;dto : ${list}&amp;quot;&amp;gt;
    &amp;lt;td th:text=&amp;quot;${dto.myno}&amp;quot;&amp;gt;myno&amp;lt;/td&amp;gt;
    &amp;lt;td th:text=&amp;quot;${dto.myname}&amp;quot;&amp;gt;myname&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;
        &amp;lt;a th:href=&amp;quot;@{/board/detail(myno=${dto.myno})}&amp;quot; th:text=&amp;quot;${dto.mytitle}&amp;quot;&amp;gt;
            mytitle
        &amp;lt;/a&amp;gt;
    &amp;lt;/td&amp;gt;
    &amp;lt;td th:text=&amp;quot;${dto.mydate}&amp;quot;&amp;gt;mydate&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;상세, 수정 화면에서는 &lt;code&gt;th:object&lt;/code&gt;와 &lt;code&gt;*{}&lt;/code&gt; 문법을 사용했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;form action=&amp;quot;/board/update&amp;quot; method=&amp;quot;post&amp;quot; th:object=&amp;quot;${dto}&amp;quot;&amp;gt;
    &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;myno&amp;quot; th:value=&amp;quot;*{myno}&amp;quot;&amp;gt;
    &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;mytitle&amp;quot; th:value=&amp;quot;*{mytitle}&amp;quot;&amp;gt;
    &amp;lt;textarea name=&amp;quot;mycontent&amp;quot; th:text=&amp;quot;*{mycontent}&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;th:object=&amp;quot;${dto}&amp;quot;&lt;/code&gt;를 지정하면 내부에서 &lt;code&gt;*{mytitle}&lt;/code&gt;처럼 간단히 접근할 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;9. 개인적으로 추가해본 삭제 알림&lt;/h1&gt;
&lt;p&gt;수업 핵심 내용은 아니지만, 삭제 후 알림을 띄우는 기능도 추가해봤다.&lt;/p&gt;
&lt;p&gt;Controller에서 삭제 후 메시지 파라미터를 붙여 redirect했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@GetMapping(&amp;quot;/delete&amp;quot;)
public String delete(int myno) {
    dao.delBoard(myno);
    return &amp;quot;redirect:/board/list?msg=delete&amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;목록 페이지에서는 &lt;code&gt;msg=delete&lt;/code&gt;가 있으면 alert를 띄운다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script th:if=&amp;quot;${param.msg != null and param.msg[0] == &amp;#39;delete&amp;#39;}&amp;quot;&amp;gt;
    alert(&amp;quot;삭제 완료!&amp;quot;);
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Controller는 브라우저 alert를 직접 띄울 수 없기 때문에, 메시지를 URL로 넘기고 View에서 JavaScript로 처리했다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;정리&lt;/h1&gt;
&lt;p&gt;오늘은 Spring Data JPA로 게시판 CRUD 흐름을 구현했다.&lt;/p&gt;
&lt;p&gt;핵심은 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Entity
- DB 테이블과 연결되는 Java 객체

JpaRepository
- 기본 CRUD 메서드를 제공하는 Repository

findBy필드명
- 메서드 이름으로 조건 조회 쿼리 생성

JPQL
- 테이블/컬럼명이 아니라 Entity/필드명을 사용

save()
- 기본키 상태에 따라 insert 또는 update 처리

Thymeleaf
- Entity 데이터를 화면에 출력하고 form으로 다시 전달&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MyBatis는 SQL을 직접 작성하는 느낌이 강했고, JPA는 객체와 메서드 이름을 중심으로 DB 작업을 처리한다는 점이 가장 큰 차이였다.&lt;/p&gt;</description>
      <category>멀티캠퍼스</category>
      <category>[현대이지웰] Java 풀스택 개발자 아카데미 8회차</category>
      <category>멀티캠퍼스부트캠프</category>
      <category>부트캠프</category>
      <author>buckwheat</author>
      <guid isPermaLink="true">https://buckwheat0.tistory.com/78</guid>
      <comments>https://buckwheat0.tistory.com/78#entry78comment</comments>
      <pubDate>Wed, 8 Jul 2026 17:27:38 +0900</pubDate>
    </item>
    <item>
      <title>[2026.07.07] - TIL 67일차 (JSP 게시판을 Thymeleaf로 전환하기)</title>
      <link>https://buckwheat0.tistory.com/77</link>
      <description>&lt;p&gt;&lt;code&gt;StartBoot02_Thymeleaf&lt;/code&gt; 프로젝트에서 기존 JSP 게시판 화면을 Thymeleaf 템플릿으로 바꾸는 작업을 했다.&lt;br&gt;기존 Controller, Biz, Dao, Mapper 구조는 유지하고, View 영역만 JSP에서 Thymeleaf HTML로 전환하는 흐름이었다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;1. JSP와 Thymeleaf의 차이&lt;/h1&gt;
&lt;p&gt;JSP에서는 데이터를 출력할 때 &lt;code&gt;${}&lt;/code&gt;를 HTML 안에 직접 작성했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsp&quot;&gt;${dto.mytitle}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thymeleaf에서는 HTML 태그의 &lt;code&gt;th:*&lt;/code&gt; 속성을 사용한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;td th:text=&amp;quot;${dto.mytitle}&amp;quot;&amp;gt;제목&amp;lt;/td&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thymeleaf의 장점은 HTML 파일 자체가 브라우저에서도 어느 정도 자연스럽게 보인다는 점이다.&lt;br&gt;&lt;code&gt;제목&lt;/code&gt; 같은 기본 텍스트를 넣어두면 서버 없이 열었을 때도 화면 구조를 확인할 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;2. Thymeleaf 기본 선언&lt;/h1&gt;
&lt;p&gt;Thymeleaf 문법을 사용하려면 HTML 태그에 네임스페이스를 선언한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;html xmlns:th=&amp;quot;http://www.thymeleaf.org&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 선언을 해야 &lt;code&gt;th:text&lt;/code&gt;, &lt;code&gt;th:href&lt;/code&gt;, &lt;code&gt;th:action&lt;/code&gt;, &lt;code&gt;th:onclick&lt;/code&gt; 같은 Thymeleaf 속성을 명확하게 사용할 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;3. 목록 페이지 구현&lt;/h1&gt;
&lt;p&gt;게시글 목록은 Controller에서 &lt;code&gt;list&lt;/code&gt;라는 이름으로 전달된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;model.addAttribute(&amp;quot;list&amp;quot;, biz.selectList());
return &amp;quot;myboardlist&amp;quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thymeleaf에서는 &lt;code&gt;th:each&lt;/code&gt;로 목록을 반복 출력한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;tr th:each=&amp;quot;dto : ${list}&amp;quot;&amp;gt;
    &amp;lt;td th:text=&amp;quot;${dto.myno}&amp;quot;&amp;gt;번호&amp;lt;/td&amp;gt;
    &amp;lt;td th:text=&amp;quot;${dto.myname}&amp;quot;&amp;gt;작성자&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;
        &amp;lt;a th:text=&amp;quot;${dto.mytitle}&amp;quot; th:href=&amp;quot;@{/myboard/detail(myno=${dto.myno})}&amp;quot;&amp;gt;
            제목
        &amp;lt;/a&amp;gt;
    &amp;lt;/td&amp;gt;
    &amp;lt;td th:text=&amp;quot;${dto.mydate}&amp;quot;&amp;gt;날짜&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기서 &lt;code&gt;${list}&lt;/code&gt;는 Model에 담긴 게시글 목록이고, &lt;code&gt;dto&lt;/code&gt;는 반복 중인 게시글 하나를 의미한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;4. &lt;code&gt;${}&lt;/code&gt;와 &lt;code&gt;@{}&lt;/code&gt; 차이&lt;/h1&gt;
&lt;p&gt;Thymeleaf에서 자주 쓰는 표현식은 &lt;code&gt;${}&lt;/code&gt;와 &lt;code&gt;@{}&lt;/code&gt;이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;${} : Model에 담긴 데이터 꺼내기
@{} : URL 만들기&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;예를 들어:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;td th:text=&amp;quot;${dto.myname}&amp;quot;&amp;gt;작성자&amp;lt;/td&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 코드는 &lt;code&gt;dto&lt;/code&gt; 객체의 &lt;code&gt;myname&lt;/code&gt; 값을 화면에 출력한다.&lt;/p&gt;
&lt;p&gt;반면:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;a th:href=&amp;quot;@{/myboard/detail(myno=${dto.myno})}&amp;quot;&amp;gt;상세&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 코드는 다음과 같은 URL을 만든다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/myboard/detail?myno=1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;즉, &lt;code&gt;$&lt;/code&gt;는 데이터, &lt;code&gt;@&lt;/code&gt;는 주소라고 생각하면 이해하기 쉽다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;5. 상세 페이지 구현&lt;/h1&gt;
&lt;p&gt;상세 페이지에서는 Controller에서 &lt;code&gt;dto&lt;/code&gt; 하나만 전달한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;model.addAttribute(&amp;quot;dto&amp;quot;, biz.selectOne(myno));
return &amp;quot;myboarddetail&amp;quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;따라서 반복문 없이 &lt;code&gt;${dto.필드명}&lt;/code&gt;으로 출력하면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;td th:text=&amp;quot;${dto.myno}&amp;quot;&amp;gt;번호&amp;lt;/td&amp;gt;
&amp;lt;td th:text=&amp;quot;${dto.myname}&amp;quot;&amp;gt;작성자&amp;lt;/td&amp;gt;
&amp;lt;td th:text=&amp;quot;${dto.mytitle}&amp;quot;&amp;gt;제목&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;
    &amp;lt;textarea rows=&amp;quot;10&amp;quot; cols=&amp;quot;40&amp;quot; readonly=&amp;quot;readonly&amp;quot; th:text=&amp;quot;${dto.mycontent}&amp;quot;&amp;gt;
        내용
    &amp;lt;/textarea&amp;gt;
&amp;lt;/td&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;수정, 삭제 버튼은 해당 글 번호를 URL에 붙여 이동한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;input type=&amp;quot;button&amp;quot; value=&amp;quot;수정&amp;quot;
    th:onclick=&amp;quot;|location.href=&amp;#39;@{/myboard/updateform(myno=${dto.myno})}&amp;#39;|&amp;quot;&amp;gt;

&amp;lt;input type=&amp;quot;button&amp;quot; value=&amp;quot;삭제&amp;quot;
    th:onclick=&amp;quot;|location.href=&amp;#39;@{/myboard/delete(myno=${dto.myno})}&amp;#39;|&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;6. 등록 페이지 구현&lt;/h1&gt;
&lt;p&gt;등록 페이지는 새 글을 입력하는 화면이므로 기존 데이터가 필요 없다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;form th:action=&amp;quot;@{/myboard/insert}&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;
    &amp;lt;table border=&amp;quot;1&amp;quot;&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th&amp;gt;작성자&amp;lt;/th&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;myname&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th&amp;gt;제목&amp;lt;/th&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;mytitle&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th&amp;gt;내용&amp;lt;/th&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;textarea rows=&amp;quot;10&amp;quot; cols=&amp;quot;40&amp;quot; name=&amp;quot;mycontent&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/table&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;name&lt;/code&gt; 값은 DTO 필드명과 맞춰야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;name=&amp;quot;myname&amp;quot;    -&amp;gt; dto.setMyname()
name=&amp;quot;mytitle&amp;quot;   -&amp;gt; dto.setMytitle()
name=&amp;quot;mycontent&amp;quot; -&amp;gt; dto.setMycontent()&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;7. 수정 페이지 구현&lt;/h1&gt;
&lt;p&gt;수정 페이지는 기존 글 정보를 화면에 먼저 출력한 뒤, 사용자가 제목과 내용을 바꿀 수 있게 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;form th:action=&amp;quot;@{/myboard/update}&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;
    &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;myno&amp;quot; th:value=&amp;quot;${dto.myno}&amp;quot;&amp;gt;

    &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;mytitle&amp;quot; th:value=&amp;quot;${dto.mytitle}&amp;quot;&amp;gt;
    &amp;lt;textarea name=&amp;quot;mycontent&amp;quot; th:text=&amp;quot;${dto.mycontent}&amp;quot;&amp;gt;내용&amp;lt;/textarea&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;수정 요청을 보낼 때는 어떤 글을 수정할지 알아야 하므로 &lt;code&gt;myno&lt;/code&gt;를 hidden input으로 함께 보낸다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;myno&amp;quot; th:value=&amp;quot;${dto.myno}&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;8. JavaScript에서 Thymeleaf 값 사용&lt;/h1&gt;
&lt;p&gt;상세 페이지에서 버튼 클릭 시 &lt;code&gt;alert&lt;/code&gt;를 띄우는 예제도 다뤘다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;input type=&amp;quot;button&amp;quot; value=&amp;quot;확인&amp;quot; onclick=&amp;quot;test();&amp;quot;&amp;gt;

&amp;lt;script type=&amp;quot;text/javascript&amp;quot; th:inline=&amp;quot;javascript&amp;quot;&amp;gt;
    function test(){
        let myno = [[${dto.myno}]];
        let myname = [[${dto.myname}]];
        alert(myno + myname);
    }
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JavaScript 안에서 Thymeleaf 값을 사용할 때는 &lt;code&gt;th:inline=&amp;quot;javascript&amp;quot;&lt;/code&gt;를 추가하고, &lt;code&gt;[[...]]&lt;/code&gt; 문법을 사용한다.&lt;/p&gt;
&lt;p&gt;실수했던 부분도 있었다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;onlcick=&amp;quot;test();&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 쓰면 오타 때문에 클릭 이벤트가 실행되지 않는다.&lt;br&gt;정확히는 아래처럼 써야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;onclick=&amp;quot;test();&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;정리&lt;/h1&gt;
&lt;p&gt;오늘은 기존 JSP 게시판 화면을 Thymeleaf 템플릿으로 바꾸면서 View 영역의 문법을 집중적으로 학습했다.&lt;/p&gt;
&lt;p&gt;핵심은 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;th:text
- 태그 안의 텍스트를 서버 데이터로 바꿈

th:each
- 리스트 반복 출력

th:href
- 링크 URL 생성

th:action
- form 요청 URL 생성

th:onclick
- 버튼 클릭 시 이동 경로 생성

${}
- Model 데이터 출력

@{}
- URL 생성

[[...]]
- JavaScript 안에서 Thymeleaf 값 사용&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JSP에서 하던 게시판 화면 처리를 Thymeleaf 방식으로 바꾸면서, Spring Boot에서는 HTML 템플릿을 더 자연스럽게 사용할 수 있다는 점을 확인했다.&lt;/p&gt;</description>
      <category>멀티캠퍼스</category>
      <category>[현대이지웰] Java 풀스택 개발자 아카데미 8회차</category>
      <category>멀티캠퍼스부트캠프</category>
      <category>부트캠프</category>
      <author>buckwheat</author>
      <guid isPermaLink="true">https://buckwheat0.tistory.com/77</guid>
      <comments>https://buckwheat0.tistory.com/77#entry77comment</comments>
      <pubDate>Tue, 7 Jul 2026 17:37:53 +0900</pubDate>
    </item>
    <item>
      <title>[2026.07.06] - TIL 66일차 (Spring Boot 게시판 보완과 Thymeleaf 시작)</title>
      <link>https://buckwheat0.tistory.com/76</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기존 &lt;code&gt;StartBoot02&lt;/code&gt; 게시판 프로젝트를 보완하고, &lt;code&gt;StartBoot03&lt;/code&gt;에서 Thymeleaf 기본 문법을 학습했다.&lt;br /&gt;기존 JSP 기반 흐름에서 Spring Boot 방식의 설정, 필터, 인터셉터, MyBatis Mapper 구조를 조금 더 정리했고, 이후 Thymeleaf 템플릿 사용법으로 넘어갔다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;1. StartBoot02 게시판 구조 보완&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;StartBoot02&lt;/code&gt;는 Spring Boot에서 Oracle DB와 MyBatis를 사용해 게시판 CRUD를 구현한 프로젝트다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 흐름은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;Controller
 -&amp;gt; Biz
 -&amp;gt; Dao
 -&amp;gt; Mapper
 -&amp;gt; DB&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 DAO 안에 SQL이 직접 들어가 있었는데, SQL을 Mapper로 분리했다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Mapper
public interface MyBoardMapper {

    @Select(&quot; SELECT * FROM MYBOARD ORDER BY MYNO DESC &quot;)
    List&amp;lt;MyDto&amp;gt; selectList();

    @Select(&quot; SELECT * FROM MYBOARD WHERE MYNO = #{myno} &quot;)
    MyDto selectOne(@Param(&quot;myno&quot;) int myno);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 DAO는 SQL을 직접 갖지 않고 Mapper를 호출하는 역할만 하게 된다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@Repository
public class MyDaoImpl implements MyDao {

    @Autowired
    private MyBoardMapper mapper;

    @Override
    public List&amp;lt;MyDto&amp;gt; selectList() {
        return mapper.selectList();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, SQL 관리는 Mapper에서 하고, DAO는 데이터 접근 흐름만 담당하게 되어 구조가 더 깔끔해진다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. Filter 설정&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot에서는 &lt;code&gt;web.xml&lt;/code&gt; 대신 Java 설정 클래스로 필터를 등록할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean&amp;lt;Filter&amp;gt; checkFilter(){
        FilterRegistrationBean&amp;lt;Filter&amp;gt; regiBean = new FilterRegistrationBean&amp;lt;Filter&amp;gt;();

        regiBean.setFilter(new Filter() {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
                System.out.println(&quot;필터 실행!&quot;);
                chain.doFilter(request, response);
            }
        });

        regiBean.addUrlPatterns(&quot;/myboard/*&quot;);
        regiBean.setOrder(1);
        return regiBean;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필터는 Controller에 도착하기 전에 먼저 실행된다.&lt;br /&gt;공통 로그 출력, 인코딩 처리, 보안 검사 같은 작업에 사용할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. Interceptor 설정&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Interceptor는 Spring MVC 내부에서 Controller 실행 전후에 동작한다.&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;public class CheckInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println(&quot;인터셉터 - 요청 uri: &quot; + request.getRequestURI());
        return true;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;preHandle()&lt;/code&gt;에서 &lt;code&gt;true&lt;/code&gt;를 반환하면 Controller가 계속 실행되고, &lt;code&gt;false&lt;/code&gt;를 반환하면 Controller로 가지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Interceptor는 &lt;code&gt;WebMvcConfigurer&lt;/code&gt;를 통해 등록한다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CheckInterceptor())
                .addPathPatterns(&quot;/myboard/*&quot;)
                .excludePathPatterns(&quot;/myboard/test&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Filter와 Interceptor의 차이는 다음처럼 정리할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;Filter      : Spring MVC 바깥에서 먼저 동작
Interceptor : Controller 실행 전후에 동작&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. StartBoot03과 Thymeleaf 시작&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;StartBoot03&lt;/code&gt;에서는 Thymeleaf 템플릿 엔진을 학습했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Thymeleaf는 HTML 안에 &lt;code&gt;th:*&lt;/code&gt; 속성을 사용해서 서버에서 전달받은 데이터를 출력하는 템플릿 엔진이다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controller에서 Model에 값을 담으면:&lt;/p&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;model.addAttribute(&quot;name&quot;, &quot;Thymeleaf!!&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML에서는 &lt;code&gt;${}&lt;/code&gt;로 값을 꺼낼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;h1 th:text=&quot;${name}&quot;&amp;gt;기본 텍스트&amp;lt;/h1&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 응답에서는 &lt;code&gt;기본 텍스트&lt;/code&gt;가 아니라 Model에 담긴 값이 출력된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;5. Thymeleaf 유틸리티 객체&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Thymeleaf에는 날짜, 숫자, 문자열 등을 처리하는 내장 유틸리티 객체가 있다.&lt;/p&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;p th:text=&quot;${#calendars.format(#calendars.createNow(), 'yyyy-MM-dd HH:mm')}&quot;&amp;gt;
    #date object
&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자 포맷도 가능하다.&lt;/p&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;p th:text=&quot;${#numbers.formatInteger(345.1234, 5)}&quot;&amp;gt;
    #numbers object
&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 처리도 지원한다.&lt;/p&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;p th:text=&quot;${#strings.toUpperCase('hello,spring boot and thymeleaf')}&quot;&amp;gt;
    #strings object
&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;6. Thymeleaf 조건문과 반복문&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건문은 &lt;code&gt;th:if&lt;/code&gt;, &lt;code&gt;th:unless&lt;/code&gt;를 사용한다.&lt;/p&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;p th:if=&quot;*{seq gt 30}&quot;&amp;gt;
    &amp;lt;span&amp;gt;seq가 30보다 크다&amp;lt;/span&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;p th:unless=&quot;*{seq gt 30}&quot;&amp;gt;
    &amp;lt;span&amp;gt;seq가 30보다 작다&amp;lt;/span&amp;gt;
&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복문은 &lt;code&gt;th:each&lt;/code&gt;를 사용한다.&lt;/p&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;tr th:each=&quot;dto : ${list}&quot;&amp;gt;
    &amp;lt;td th:text=&quot;${dto.subject}&quot;&amp;gt;과목&amp;lt;/td&amp;gt;
    &amp;lt;td th:text=&quot;${dto.seq}&quot;&amp;gt;번호&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSP의 &lt;code&gt;c:forEach&lt;/code&gt;와 비슷한 역할이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;정리&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot 게시판 프로젝트를 보완하면서 Filter, Interceptor, Mapper 구조를 정리했고, 이후 Thymeleaf 기본 문법을 학습했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Mapper
- SQL을 따로 분리해서 관리

Filter
- Controller 이전에 실행되는 공통 처리

Interceptor
- Controller 실행 전후에 동작

Thymeleaf
- HTML 기반 템플릿 엔진
- th:text, th:each, th:if 등으로 서버 데이터를 출력&lt;/code&gt;&lt;/pre&gt;</description>
      <category>멀티캠퍼스</category>
      <category>[현대이지웰] Java 풀스택 개발자 아카데미 8회차</category>
      <category>멀티캠퍼스부트캠프</category>
      <category>부트캠프</category>
      <author>buckwheat</author>
      <guid isPermaLink="true">https://buckwheat0.tistory.com/76</guid>
      <comments>https://buckwheat0.tistory.com/76#entry76comment</comments>
      <pubDate>Tue, 7 Jul 2026 17:35:29 +0900</pubDate>
    </item>
    <item>
      <title>[26.06.29-26.07.03] TIL 14주차 정리</title>
      <link>https://buckwheat0.tistory.com/75</link>
      <description>&lt;h1&gt;&lt;b&gt;Spring MVC부터 Spring Boot JDBC까지 한 주 정리&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주에는 Spring MVC 프로젝트에 공통 처리 기능을 붙이고, 파일 업로드와 REST API를 만든 뒤 Spring Boot 방식으로 넘어가는 흐름을 학습했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리 범위는 다음 프로젝트다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;SpringMVC03_filter_aop_login_intercepter_transaction_encoding&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SpringMVC04_file&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SpringMVC05_REST&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StartBoot01&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StartBoot02&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;1. Spring MVC 기본 흐름&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring MVC는 사용자의 요청을 &lt;code&gt;Controller&lt;/code&gt;가 받고, 필요한 로직은 &lt;code&gt;Biz(Service)&lt;/code&gt;와 &lt;code&gt;Dao&lt;/code&gt;를 거쳐 처리한 뒤 JSP 화면으로 응답하는 구조다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;브라우저 요청
 -&amp;gt; DispatcherServlet
 -&amp;gt; Controller
 -&amp;gt; Biz(Service)
 -&amp;gt; Dao
 -&amp;gt; DB
 -&amp;gt; JSP 응답&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목록 조회에서는 DB에서 가져온 데이터를 &lt;code&gt;Model&lt;/code&gt;에 담아 JSP로 넘긴다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@RequestMapping(&quot;/list.do&quot;)
public String selectList(Model model) {
    model.addAttribute(&quot;list&quot;, biz.selectList());
    return &quot;mvclist&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Model&lt;/code&gt;은 Controller에서 JSP로 데이터를 전달할 때 사용한다.&lt;br /&gt;위 코드에서는 게시글 목록을 &lt;code&gt;list&lt;/code&gt;라는 이름으로 JSP에 넘긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등록, 수정, 삭제 후에는 보통 &lt;code&gt;redirect&lt;/code&gt;를 사용한다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@RequestMapping(&quot;/insertres.do&quot;)
public String insert(BoardDto dto) {
    int res = biz.insert(dto);

    if (res &amp;gt; 0) {
        return &quot;redirect:list.do&quot;;
    } else {
        return &quot;redirect:insertform.do&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;redirect&lt;/code&gt;는 서버 내부 이동이 아니라 브라우저에게 다시 요청할 주소를 알려주는 방식이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;2. Filter&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Filter는 Controller에 도착하기 전에 먼저 실행되는 공통 처리 단계다.&lt;br /&gt;이번 프로젝트에서는 한글 깨짐 방지와 요청 로그 출력에 사용했다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;&amp;lt;filter&amp;gt;
    &amp;lt;filter-name&amp;gt;encodingFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;filter-class&amp;gt;org.springframework.web.filter.CharacterEncodingFilter&amp;lt;/filter-class&amp;gt;
    &amp;lt;init-param&amp;gt;
        &amp;lt;param-name&amp;gt;encoding&amp;lt;/param-name&amp;gt;
        &amp;lt;param-value&amp;gt;UTF-8&amp;lt;/param-value&amp;gt;
    &amp;lt;/init-param&amp;gt;
    &amp;lt;init-param&amp;gt;
        &amp;lt;param-name&amp;gt;forceEncoding&amp;lt;/param-name&amp;gt;
        &amp;lt;param-value&amp;gt;true&amp;lt;/param-value&amp;gt;
    &amp;lt;/init-param&amp;gt;
&amp;lt;/filter&amp;gt;

&amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;encodingFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;
&amp;lt;/filter-mapping&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;forceEncoding=true&lt;/code&gt;는 요청과 응답에 UTF-8 인코딩을 강제로 적용하겠다는 의미다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 만든 &lt;code&gt;LogFilter&lt;/code&gt;에서는 요청 URI, URL, 브라우저 정보 등을 로그로 남겼다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest) request;

    String uri = req.getRequestURI();
    String agent = req.getHeader(&quot;User-Agent&quot;);

    logger.info(&quot;URI: &quot; + uri);
    logger.info(&quot;agent: &quot; + agent);

    chain.doFilter(req, response);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;chain.doFilter()&lt;/code&gt;를 호출해야 다음 단계인 DispatcherServlet과 Controller로 요청이 계속 이동한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;3. AOP&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AOP는 여러 곳에서 반복되는 공통 기능을 따로 분리하는 방식이다.&lt;br /&gt;대표적으로 로그 출력, 트랜잭션 처리, 예외 처리 같은 기능에 사용한다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;핵심 로직: 게시글 등록, 수정, 삭제
공통 로직: 로그, 트랜잭션, 예외 처리&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 메서드에 로그 코드를 직접 작성하면 코드가 지저분해진다.&lt;br /&gt;AOP를 사용하면 핵심 로직은 그대로 두고, 공통 로직만 별도 클래스로 관리할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;4. 로그인과 비밀번호 암호화&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회원가입 시 비밀번호를 그대로 DB에 저장하지 않고 &lt;code&gt;BCryptPasswordEncoder&lt;/code&gt;로 암호화했다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;String encode = passwordEncoder.encode(dto.getMemberpw());
dto.setMemberpw(encode);

int res = biz.insert(dto);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인할 때는 사용자가 입력한 비밀번호와 DB에 저장된 암호화 비밀번호를 비교한다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;if (res != null) {
    if (passwordEncoder.matches(dto.getMemberpw(), res.getMemberpw())) {
        session.setAttribute(&quot;login&quot;, res);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;matches()&lt;/code&gt;는 평문 비밀번호와 암호화된 비밀번호가 같은 값인지 확인해준다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;5. Interceptor&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Interceptor는 Spring MVC 안에서 Controller 실행 전후에 동작한다.&lt;br /&gt;이번 프로젝트에서는 로그인 여부를 확인하는 데 사용했다.&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws IOException {

    if (request.getSession().getAttribute(&quot;login&quot;) != null) {
        return true;
    }

    response.sendRedirect(&quot;loginform.do&quot;);
    return false;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;preHandle()&lt;/code&gt;에서 &lt;code&gt;true&lt;/code&gt;를 반환하면 Controller가 실행되고, &lt;code&gt;false&lt;/code&gt;를 반환하면 Controller로 가지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Filter와 Interceptor의 차이는 다음과 같이 볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;Filter: Spring MVC 바깥에서 먼저 처리
Interceptor: Spring MVC 안에서 Controller 전후 처리&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;6. Transaction&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션은 여러 DB 작업을 하나의 작업 단위로 묶는 개념이다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Service
@Transactional
public class BoardBizImpl implements BoardBiz {
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB 작업이 모두 성공하면 &lt;code&gt;commit&lt;/code&gt;, 중간에 실패하면 &lt;code&gt;rollback&lt;/code&gt;된다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;모두 성공 -&amp;gt; commit
중간 실패 -&amp;gt; rollback&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 insert 작업을 여러 번 수행하는 중 하나가 실패하면, 앞에서 성공한 작업까지 취소해서 데이터가 애매하게 남지 않도록 한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;7. 파일 업로드&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 업로드에서는 일반 form 전송과 다르게 &lt;code&gt;multipart/form-data&lt;/code&gt; 설정이 필요하다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;&amp;lt;form action=&quot;upload&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&amp;gt;
    &amp;lt;input type=&quot;file&quot; name=&quot;mpfile&quot;&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controller에서는 &lt;code&gt;MultipartFile&lt;/code&gt;로 파일을 받는다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@RequestMapping(&quot;/upload&quot;)
public String fileUpload(UploadFile uploadFile, BindingResult result, Model model) {
    fileValidator.validate(uploadFile, result);

    if (result.hasErrors()) {
        return &quot;uploadform&quot;;
    }

    MultipartFile file = uploadFile.getMpfile();

    UploadFile fileobj = new UploadFile();
    fileobj.setFilename(file.getOriginalFilename());
    fileobj.setDesc(uploadFile.getDesc());

    model.addAttribute(&quot;fileobj&quot;, fileobj);
    return &quot;uploadres&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일을 서버 폴더에 저장할 때는 &lt;code&gt;InputStream&lt;/code&gt;과 &lt;code&gt;OutputStream&lt;/code&gt;을 사용했다.&lt;/p&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;inputStream = file.getInputStream();
outputStream = new FileOutputStream(newFile);

byte[] b = new byte[(int) file.getSize()];

while ((res = inputStream.read(b)) != -1) {
    outputStream.write(b, 0, res);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 업로드 흐름은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;파일 선택
 -&amp;gt; multipart/form-data 전송
 -&amp;gt; MultipartFile로 받기
 -&amp;gt; 유효성 검사
 -&amp;gt; 서버 폴더에 저장
 -&amp;gt; 결과 화면 출력&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;8. REST API&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST는 JSP 화면을 반환하는 것이 아니라 데이터를 반환하는 방식이다.&lt;br /&gt;이번 프로젝트에서는 &lt;code&gt;@RestController&lt;/code&gt;를 사용해 JSON 데이터를 응답했다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@RestController
public class RestControllerTest {

    @RequestMapping(value=&quot;/restdto&quot;, method=RequestMethod.GET)
    public List&amp;lt;RestDto&amp;gt; getRest() {
        return service.selectList();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Controller&lt;/code&gt;는 주로 JSP 화면 이름을 반환하고, &lt;code&gt;@RestController&lt;/code&gt;는 반환값 자체를 응답 데이터로 보낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST에서 자주 쓰는 HTTP 메서드는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;GET    조회
POST   등록
PUT    수정
DELETE 삭제&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등록 요청은 &lt;code&gt;POST&lt;/code&gt;로 처리했다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;@RequestMapping(value=&quot;/restdto&quot;, method=RequestMethod.POST)
public Map&amp;lt;String, Integer&amp;gt; postRest(RestDto dto) {
    int res = service.insert(dto);

    Map&amp;lt;String, Integer&amp;gt; map = new HashMap&amp;lt;String, Integer&amp;gt;();

    if (res &amp;gt; 0) {
        map.put(&quot;code&quot;, 200);
    } else {
        map.put(&quot;code&quot;, 500);
    }

    return map;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Map&amp;lt;String, Integer&amp;gt;&lt;/code&gt;는 key는 문자열, value는 정수인 데이터 구조다.&lt;br /&gt;위 코드는 다음과 같은 JSON 응답으로 변환될 수 있다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;code&quot;: 200
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;9. Spring Boot 시작&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;StartBoot01&lt;/code&gt;에서는 Spring Boot의 기본 실행 구조를 확인했다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@SpringBootApplication
public class StartBoot01Application {

    public static void main(String[] args) {
        SpringApplication.run(StartBoot01Application.class, args);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 Spring MVC는 외부 Tomcat에 프로젝트를 올리고 &lt;code&gt;web.xml&lt;/code&gt;, &lt;code&gt;servlet-context.xml&lt;/code&gt; 같은 설정을 많이 작성했다.&lt;br /&gt;Spring Boot는 내장 Tomcat을 사용하기 때문에 main 메서드로 바로 실행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSP를 사용하려면 view 경로 설정이 필요하다.&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controller에서 &lt;code&gt;return &quot;test&quot;;&lt;/code&gt;를 하면 실제로는 다음 JSP를 찾는다.&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;/WEB-INF/views/test.jsp&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;10. Spring Boot + JDBC&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;StartBoot02&lt;/code&gt;에서는 Spring Boot에서 JDBC를 사용해 게시판 CRUD를 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB 연결 정보는 &lt;code&gt;application.properties&lt;/code&gt;에 작성한다.&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;server.port=8787

spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521/XEPDB1
spring.datasource.username=multi
spring.datasource.password=multi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DAO에서는 &lt;code&gt;JdbcTemplate&lt;/code&gt;을 사용했다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@Repository
public class MyDaoImpl implements MyDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public List&amp;lt;MyDto&amp;gt; selectList() {
        String sql = &quot; SELECT * FROM MYBOARD ORDER BY MYNO DESC &quot;;
        return jdbcTemplate.query(sql, rowMapper);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;JdbcTemplate&lt;/code&gt;은 JDBC 코드를 더 간단하게 작성할 수 있게 해준다.&lt;br /&gt;직접 &lt;code&gt;Connection&lt;/code&gt;, &lt;code&gt;PreparedStatement&lt;/code&gt;, &lt;code&gt;ResultSet&lt;/code&gt;을 매번 열고 닫는 코드를 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controller에서는 요청을 받아 Biz를 호출하고, 결과를 JSP로 넘긴다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@GetMapping(&quot;/list&quot;)
public String selectList(Model model) {
    model.addAttribute(&quot;list&quot;, biz.selectList());
    return &quot;myboardlist&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등록은 &lt;code&gt;POST&lt;/code&gt; 요청으로 처리했다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@PostMapping(&quot;/insert&quot;)
public String insert(MyDto dto) {
    int res = biz.insert(dto);

    if (res &amp;gt; 0) {
        return &quot;redirect:/myboard/list&quot;;
    } else {
        return &quot;redirect:/myboard/insertform&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot에서도 전체 구조는 기존 MVC와 비슷하다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;Controller
 -&amp;gt; Biz
 -&amp;gt; Dao
 -&amp;gt; JdbcTemplate
 -&amp;gt; Oracle DB&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차이점은 설정 방식이다.&lt;br /&gt;기존 Spring MVC는 XML 설정이 많았고, Spring Boot는 &lt;code&gt;application.properties&lt;/code&gt;와 자동 설정을 중심으로 동작한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 단순 CRUD에서 끝나는 것이 아니라 웹 애플리케이션에 필요한 공통 기능들을 하나씩 붙여보는 시간이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심만 정리하면 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;Filter
- Controller 전에 실행되는 공통 처리
- 인코딩, 로그 처리 등에 사용

AOP
- 반복되는 공통 기능 분리
- 로그, 트랜잭션 등에 사용

Interceptor
- Controller 실행 전후에 동작
- 로그인 체크에 적합

Transaction
- 여러 DB 작업을 하나의 단위로 묶음
- 실패 시 rollback

File Upload
- multipart/form-data 필요
- MultipartFile로 파일 처리

REST
- JSP가 아니라 데이터를 응답
- GET, POST, PUT, DELETE 사용

Spring Boot
- 내장 Tomcat으로 실행
- application.properties 중심 설정
- 기존 Spring MVC보다 설정이 간단함&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체적으로 이번 주 학습 내용은 Spring MVC 프로젝트를 실제 웹 애플리케이션에 가깝게 확장하고, 이후 Spring Boot 방식으로 전환하는 흐름이었다.&lt;/p&gt;</description>
      <category>멀티캠퍼스/주차별 정리</category>
      <category>[현대이지웰] Java 풀스택 개발자 아카데미 8회차</category>
      <category>멀티캠퍼스부트캠프</category>
      <category>부트캠프</category>
      <author>buckwheat</author>
      <guid isPermaLink="true">https://buckwheat0.tistory.com/75</guid>
      <comments>https://buckwheat0.tistory.com/75#entry75comment</comments>
      <pubDate>Sun, 5 Jul 2026 15:07:56 +0900</pubDate>
    </item>
    <item>
      <title>[26.06.22-26.06.26] TIL 13주차 정리</title>
      <link>https://buckwheat0.tistory.com/74</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/69&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://buckwheat0.tistory.com/69&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782808002567&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[2026.06.22] - TIL 56일차 Spring MVC 기본 구조 정리&quot; data-og-description=&quot;목차1 오늘 학습 흐름2 Spring MVC 프로젝트 구조3 pom.xml과 Spring MVC 의존성4 web.xml의 역할5 DispatcherServlet6 ContextLoaderListener7 Root Context와 Servlet Context8 Controller9 @RequestMapping10 Model11 ModelAndView12 @RequestParam1&quot; data-og-host=&quot;buckwheat0.tistory.com&quot; data-og-source-url=&quot;https://buckwheat0.tistory.com/69&quot; data-og-url=&quot;https://buckwheat0.tistory.com/69&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dl3GvV/dJMb9cBSFE4/6dAb7dymEYlua63sQcseD0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/c8fiKh/dJMb9g5lGpc/GcQrIksX7NKwYX9LRWADi1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gKdzX/dJMb89yooBh/lnTvltX4DjHe5CFkuZNJo1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/69&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://buckwheat0.tistory.com/69&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dl3GvV/dJMb9cBSFE4/6dAb7dymEYlua63sQcseD0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/c8fiKh/dJMb9g5lGpc/GcQrIksX7NKwYX9LRWADi1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gKdzX/dJMb89yooBh/lnTvltX4DjHe5CFkuZNJo1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[2026.06.22] - TIL 56일차 Spring MVC 기본 구조 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;목차1 오늘 학습 흐름2 Spring MVC 프로젝트 구조3 pom.xml과 Spring MVC 의존성4 web.xml의 역할5 DispatcherServlet6 ContextLoaderListener7 Root Context와 Servlet Context8 Controller9 @RequestMapping10 Model11 ModelAndView12 @RequestParam1&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;buckwheat0.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/70&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://buckwheat0.tistory.com/70&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782808014827&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[2026.06.23] - TIL 57일차(Spring MVC03 게시판 프로젝트 완성)&quot; data-og-description=&quot;목차1 Spring MVC 프로젝트 구조2 MyBatis를 활용한 게시판 구현3 View(JSP) 작성4 Spring 설정 파일5 프로젝트 실행 흐름6 오류 해결 과정1 Spring MVC 프로젝트 구조1) Spring MVC 패턴 이해Spring MVC는 프로젝트를 &quot; data-og-host=&quot;buckwheat0.tistory.com&quot; data-og-source-url=&quot;https://buckwheat0.tistory.com/70&quot; data-og-url=&quot;https://buckwheat0.tistory.com/70&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dfNHAo/dJMb9llhLIK/QMA9L26hVkzGrcIBWRKxI1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/hdH1y/dJMb8WMAtaE/s9QF3mJ5zaKsR7O8SXmtV0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bnhOSw/dJMb9ia1Oga/zXtjJkulytXxVwupKOcXy0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/70&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://buckwheat0.tistory.com/70&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dfNHAo/dJMb9llhLIK/QMA9L26hVkzGrcIBWRKxI1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/hdH1y/dJMb8WMAtaE/s9QF3mJ5zaKsR7O8SXmtV0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bnhOSw/dJMb9ia1Oga/zXtjJkulytXxVwupKOcXy0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[2026.06.23] - TIL 57일차(Spring MVC03 게시판 프로젝트 완성)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;목차1 Spring MVC 프로젝트 구조2 MyBatis를 활용한 게시판 구현3 View(JSP) 작성4 Spring 설정 파일5 프로젝트 실행 흐름6 오류 해결 과정1 Spring MVC 프로젝트 구조1) Spring MVC 패턴 이해Spring MVC는 프로젝트를&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;buckwheat0.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://buckwheat0.tistory.com/71&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782808025723&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[2026.06.24] - TIL 58일차 개발자를 위한 UI/UX 특강 정리&quot; data-og-description=&quot;목차1 오늘 학습 흐름2 UI/UX 특강 개요3 UI와 UX의 차이4 페르소나5 고객 여정 지도6 사이트맵7 와이어프레임8 프로토타입9 CodeMate 서비스 기획10 고객 여정 지도 설계 내용11 사이트맵 설계 내용12 Figm&quot; data-og-host=&quot;buckwheat0.tistory.com&quot; data-og-source-url=&quot;https://buckwheat0.tistory.com/71&quot; data-og-url=&quot;https://buckwheat0.tistory.com/71&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/z9SAO/dJMb81G8gcG/DXYphBPTCX7DcV708uROP1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bDNVjT/dJMb8XSgEDt/YtSyKkLrWiBIrhvgeizQX0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/tJ8fQ/dJMb82MNVyl/2iDzTrJlkK8XkKG48gHKvk/img.png?width=1716&amp;amp;height=917&amp;amp;face=0_0_1716_917&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://buckwheat0.tistory.com/71&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/z9SAO/dJMb81G8gcG/DXYphBPTCX7DcV708uROP1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bDNVjT/dJMb8XSgEDt/YtSyKkLrWiBIrhvgeizQX0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/tJ8fQ/dJMb82MNVyl/2iDzTrJlkK8XkKG48gHKvk/img.png?width=1716&amp;amp;height=917&amp;amp;face=0_0_1716_917');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[2026.06.24] - TIL 58일차 개발자를 위한 UI/UX 특강 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;목차1 오늘 학습 흐름2 UI/UX 특강 개요3 UI와 UX의 차이4 페르소나5 고객 여정 지도6 사이트맵7 와이어프레임8 프로토타입9 CodeMate 서비스 기획10 고객 여정 지도 설계 내용11 사이트맵 설계 내용12 Figm&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;buckwheat0.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/73&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://buckwheat0.tistory.com/73&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782808035639&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[2026.06.25 ~ 2026.06.26] - TIL 59~60일차 MSA 특강 정리&quot; data-og-description=&quot;목차1 MSA란 무엇인가2 모놀리식 아키텍처와 MSA3 MSA의 주요 특징4 MSA 전환 사례5 MSA를 무조건 선택하면 안 되는 이유6 MSA 이전 방법론7 소프트웨어 아키텍처 구성 요소8 ADR9 서비스 기반 아키텍처10 &quot; data-og-host=&quot;buckwheat0.tistory.com&quot; data-og-source-url=&quot;https://buckwheat0.tistory.com/73&quot; data-og-url=&quot;https://buckwheat0.tistory.com/73&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bcM8Tk/dJMb9aKPKD6/LiYVDtZObwj6j9Gda8rNMk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cUBMPv/dJMb83kDNod/y55pc8Rj90I21KEK7WrSU1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/8jM05/dJMb88GfO1P/XwpbE74duiAEEay9l8fkM0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://buckwheat0.tistory.com/73&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://buckwheat0.tistory.com/73&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bcM8Tk/dJMb9aKPKD6/LiYVDtZObwj6j9Gda8rNMk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cUBMPv/dJMb83kDNod/y55pc8Rj90I21KEK7WrSU1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/8jM05/dJMb88GfO1P/XwpbE74duiAEEay9l8fkM0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[2026.06.25 ~ 2026.06.26] - TIL 59~60일차 MSA 특강 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;목차1 MSA란 무엇인가2 모놀리식 아키텍처와 MSA3 MSA의 주요 특징4 MSA 전환 사례5 MSA를 무조건 선택하면 안 되는 이유6 MSA 이전 방법론7 소프트웨어 아키텍처 구성 요소8 ADR9 서비스 기반 아키텍처10&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;buckwheat0.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>멀티캠퍼스/주차별 정리</category>
      <category>[현대이지웰] Java 풀스택 개발자 아카데미 8회차</category>
      <category>멀티캠퍼스부트캠프</category>
      <category>부트캠프</category>
      <author>buckwheat</author>
      <guid isPermaLink="true">https://buckwheat0.tistory.com/74</guid>
      <comments>https://buckwheat0.tistory.com/74#entry74comment</comments>
      <pubDate>Tue, 30 Jun 2026 17:27:24 +0900</pubDate>
    </item>
    <item>
      <title>[2026.06.25 ~ 2026.06.26] - TIL 59~60일차 MSA 특강 정리</title>
      <link>https://buckwheat0.tistory.com/73</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;목차&lt;br /&gt;1 MSA란 무엇인가&lt;br /&gt;2 모놀리식 아키텍처와 MSA&lt;br /&gt;3 MSA의 주요 특징&lt;br /&gt;4 MSA 전환 사례&lt;br /&gt;5 MSA를 무조건 선택하면 안 되는 이유&lt;br /&gt;6 MSA 이전 방법론&lt;br /&gt;7 소프트웨어 아키텍처 구성 요소&lt;br /&gt;8 ADR&lt;br /&gt;9 서비스 기반 아키텍처&lt;br /&gt;10 이벤트 기반 아키텍처&lt;br /&gt;11 마이크로서비스 아키텍처&lt;br /&gt;12 DDD와 마이크로서비스 설계&lt;br /&gt;13 이벤트 스토밍&lt;br /&gt;14 아키텍처 도식화와 C4 Model&lt;br /&gt;15 Spring Cloud&lt;br /&gt;16 Docker 기본 개념&lt;br /&gt;17 Docker 주요 실습&lt;br /&gt;18 Docker Swarm&lt;br /&gt;19 Kubernetes&lt;br /&gt;20 Kubernetes 주요 오브젝트&lt;br /&gt;21 Ingress와 Service Mesh&lt;br /&gt;22 CI/CD&lt;br /&gt;23 학습 내용 정리&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1 MSA란 무엇인가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) MSA의 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) MSA&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;MSA는 Microservices Architecture의 줄임말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;하나의 큰 애플리케이션을 여러 개의 작은 서비스로 나누고, 각 서비스가 독립적으로 실행되고 배포될 수 있도록 구성하는 아키텍처이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Microservice&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;마이크로서비스는 하나의 비즈니스 기능을 담당하는 작은 서비스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;예를 들어 쇼핑몰이라면 회원 서비스, 주문 서비스, 결제 서비스, 배송 서비스처럼 나눌 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 핵심&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;MSA의 핵심은 큰 시스템을 작게 나누는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;하지만 단순히 코드를 작게 나누는 것이 아니라, 비즈니스 기능 단위로 나누고 각 서비스가 독립적으로 개발, 배포, 확장될 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) MSA의 기본 구조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 독립 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;각 마이크로서비스는 자기 자신의 프로세스에서 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;하나의 서비스가 죽더라도 전체 시스템이 모두 멈추지 않도록 설계할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 가벼운 통신&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스들은 HTTP API, 메시지 큐, 이벤트 등을 통해 통신한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;직접 메소드 호출처럼 강하게 묶이는 방식보다 느슨하게 연결되는 구조를 지향한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 독립 배포&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;각 서비스는 독립적으로 배포할 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;주문 서비스만 수정했다면 전체 시스템을 다시 배포하는 것이 아니라 주문 서비스만 배포할 수 있어야 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2 모놀리식 아키텍처와 MSA&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 모놀리식 아키텍처&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;모놀리식 아키텍처는 하나의 애플리케이션 안에 모든 기능이 들어 있는 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;회원, 주문, 결제, 배송 기능이 하나의 프로젝트와 하나의 배포 단위 안에 들어가는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 장점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스 규모가 작을 때는 구조가 단순하고 개발하기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;한 프로젝트 안에서 모든 기능을 볼 수 있고, 배포도 하나만 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 단점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;시스템이 커지면 코드베이스가 비대해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;한 기능의 문제가 전체 장애로 이어질 수 있고, 작은 수정에도 전체 시스템을 다시 배포해야 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) MSA&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;MSA는 큰 시스템을 작은 서비스들로 나눈 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;각 서비스는 독립된 기능을 담당하고, 필요한 경우 서로 API나 메시지로 통신한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 장점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스별로 독립 개발, 독립 배포, 독립 확장이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;한 서비스에 장애가 발생해도 전체 시스템으로 장애가 번지는 것을 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 단점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스가 많아지면 통신 구조, 배포 구조, 모니터링, 로그 관리, 장애 대응이 복잡해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;즉, MSA는 코드를 나누는 것보다 운영 복잡도를 감당하는 것이 더 어렵다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3 MSA의 주요 특징&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) MSA의 9가지 특징&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Componentization via Services&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;기능을 라이브러리나 모듈이 아니라 서비스 단위로 나눈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;각 서비스는 독립적인 실행 단위가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Organized around Business Capabilities&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;기술 계층이 아니라 비즈니스 기능을 기준으로 서비스를 나눈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;예를 들어 Controller, Service, DAO 기준으로 나누는 것이 아니라 주문, 결제, 회원 같은 비즈니스 기준으로 나눈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) Products not Projects&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;프로젝트를 한 번 만들고 끝내는 것이 아니라, 서비스 자체를 계속 운영하고 발전시키는 제품으로 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) Smart endpoints and dumb pipes&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스 자체가 똑똑하게 비즈니스 로직을 처리하고, 통신 경로는 단순하게 유지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;복잡한 중앙 통합 장치에 모든 로직을 몰아넣지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) Decentralized Governance&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;모든 서비스가 반드시 같은 기술을 사용할 필요는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스 특성에 따라 다른 언어, 프레임워크, 저장소를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(6) Decentralized Data Management&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;하나의 중앙 DB에 모든 서비스가 붙는 것이 아니라, 서비스별로 데이터를 분리해서 관리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(7) Infrastructure Automation&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스가 많기 때문에 배포와 운영을 수동으로 처리하기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;CI/CD, 컨테이너, 오케스트레이션 같은 자동화가 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(8) Design for Failure&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;분산 시스템에서는 장애가 발생할 수밖에 없다고 보고 설계해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;일부 서비스 장애가 전체 장애로 확산되지 않도록 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(9) Evolutionary Design&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;처음부터 완벽한 설계를 고정하는 것이 아니라, 서비스가 성장하면서 점진적으로 개선할 수 있어야 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4 MSA 전환 사례&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Coupang&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 초기 구조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;쿠팡은 초기에는 Apache, Tomcat, MySQL 기반의 모놀리식 구조로 운영되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 문제점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;고객과 개발자가 급격히 늘어나면서 확장성 문제가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;한 컴포넌트의 장애가 전체 장애로 이어지고, 공통 모듈이 비대해지고, 배포와 테스트 비용이 커졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 전환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;쿠팡은 2013년부터 MSA 전환을 추진했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;자체적으로 Java 기반의 Vitamin Framework를 구축했다는 점이 특징이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 11번가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 기존 구조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;11번가는 오랫동안 초대형 모놀리식 시스템을 운영했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;오래된 소프트웨어 스택, 거대한 공통 모듈, 어려운 개발 환경, 정기 배포의 부담이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 문제점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;하나의 수정이 전체 장애로 이어질 수 있었고, IDE에 프로젝트를 띄우는 것조차 버거운 상황이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 전환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Netflix Spring Cloud와 Spring Boot 기반의 MSA 구조로 점진적으로 전환했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 카카오톡 이모티콘 서비스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 기존 문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이모티콘 서비스, 이모티콘 스튜디오, Admin 서비스들이 각각 모놀리식으로 구성되어 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;오래된 Java와 Play Framework를 사용해 기술 부채가 컸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 운영 문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;배포 방식이 서버마다 다르고, 브랜치 관리가 복잡하며, 메인 DB 트래픽이 높아지는 문제가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 전환 방향&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Kotlin, Spring, Kubernetes, Istio 등을 활용해 MSA 기반 구조로 개선했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 토스뱅크&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 기존 은행 시스템&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;일반적인 은행 시스템은 채널계와 코어뱅킹으로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;채널계는 MSA 구조를 적용하기 쉬웠지만, 코어뱅킹은 오랫동안 모놀리식 구조로 유지되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 문제점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;모놀리식 코어뱅킹은 트랜잭션 처리에는 유리하지만 스케일 아웃이 어렵고, 장애 영향 범위를 제한하기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 전환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;토스뱅크는 모바일 특화 MSA 아키텍처로 코어뱅킹을 전환했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이를 통해 도메인별 독립 개선과 빠른 기능 배포가 가능해졌다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5 MSA를 무조건 선택하면 안 되는 이유&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) MSA의 적절한 사용 시점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 작은 서비스에는 모놀리식이 유리할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스 규모가 작을 때는 모놀리식 구조가 더 단순하고 효율적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;스타트업이 MVP를 만들 때 처음부터 MSA를 선택하면 오버엔지니어링이 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) MSA가 필요한 시점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;코드베이스가 너무 커져 관리가 어렵거나, 개발자가 많아져 배포 충돌이 잦거나, 특정 기능만 독립 확장해야 할 때 MSA를 고려할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 핵심 판단 기준&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;MSA는 유행이라서 선택하는 것이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스 규모, 팀 규모, 배포 빈도, 장애 격리 필요성, 확장성 요구가 분명할 때 선택해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) MSA의 어려움&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 서비스 간 통신 복잡도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스를 나누면 각 서비스가 네트워크를 통해 통신해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;네트워크 지연, 장애, 타임아웃, 재시도 같은 문제가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 운영 복잡도 증가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스가 많아지면 로그, 모니터링, 배포, 설정 관리, 장애 추적이 어려워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 데이터 관리 복잡도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스별 DB를 분리하면 데이터 정합성을 맞추는 방식도 고민해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;하나의 트랜잭션으로 모든 처리를 끝내기 어려워질 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6 MSA 이전 방법론&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 직접 아키텍처 구축&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;기업 내부에서 자체 프레임워크와 도구를 만들어 MSA를 구축하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 장점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;필요한 부분을 원하는 방식으로 수정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;조직에 맞는 맞춤형 구조를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 단점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;충분한 인력, 시간, 예산이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이후 유지보수 비용도 계속 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) Netflix Spring Cloud 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Spring Cloud와 Netflix OSS를 활용해 MSA를 구현하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Eureka, Zuul, Ribbon, Hystrix 같은 구성 요소를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 장점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Java와 Spring Boot 기반 프로젝트에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;사례가 많고 Java 개발자에게 익숙하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 단점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Java와 Spring Boot에 종속될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;MSA 관련 코드가 소스 레벨에 포함될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) Kubernetes 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너와 Kubernetes를 기반으로 서비스를 배포하고 운영하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 장점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;언어에 종속되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Java, Python, Node.js 등 다양한 언어로 작성된 서비스를 함께 운영할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 단점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Kubernetes 자체의 학습 난이도가 높다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너, 네트워크, 배포, 운영에 대한 이해가 필요하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;7 소프트웨어 아키텍처 구성 요소&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 아키텍처를 구성하는 요소&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 아키텍처 특성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;시스템이 지원해야 하는 품질 속성이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;가용성, 신뢰성, 민첩성, 복구성, 확장성, 성능 등이 여기에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 아키텍처 결정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;시스템을 구축할 때 지켜야 하는 중요한 규칙이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;예를 들어 데이터베이스 접근은 특정 계층에서만 허용한다는 결정이 있을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 설계 원칙&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;시스템을 만들 때 따라야 할 가이드라인이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;예를 들어 서비스 간 통신은 비동기 메시징을 우선 사용한다는 원칙을 둘 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) 시스템 구조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;어떤 아키텍처 스타일을 적용했는지를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;예를 들어 레이어드 아키텍처, 이벤트 기반 아키텍처, 마이크로서비스 아키텍처가 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;8 ADR&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) ADR의 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) ADR&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;ADR은 &lt;b&gt;Architecture Decision Record&lt;/b&gt;의 줄임말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;중요한 아키텍처 결정을 문서화하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 필요한 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;왜 이런 기술을 선택했는지, 왜 이런 구조로 설계했는지 기록하지 않으면 시간이 지난 뒤 이유를 알기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;ADR은 의사결정의 배경과 결과를 남기는 문서이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) ADR의 기본 구조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 제목&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;어떤 결정을 기록하는지 짧게 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;제안됨, 수락됨, 대체됨 같은 상태를 기록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 콘텍스트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;왜 이 결정을 해야 했는지 상황을 설명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) 결정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;어떤 결정을 내렸는지와 그 이유를 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) 결과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이 결정이 시스템과 팀에 어떤 영향을 주는지 정리한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;9 서비스 기반 아키텍처&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 서비스 기반 아키텍처&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스 기반 아키텍처는 여러 원격 서비스를 사용하는 대규모 분산 레이어 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;MSA와 비슷하지만 중앙 공유 데이터베이스를 사용할 수 있다는 점이 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 특징&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;UI와 여러 서비스가 분리되어 있고, 서비스들이 공통 DB를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;MSA보다 현실적으로 도입하기 쉬운 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) MSA와의 차이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;MSA는 서비스별로 데이터까지 분리하는 방향을 지향한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스 기반 아키텍처는 중앙 공유 DB를 사용할 수 있어 데이터 분리 강도가 MSA보다 약하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;10 이벤트 기반 아키텍처&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 이벤트 기반 아키텍처&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이벤트 기반 아키텍처는 이벤트를 중심으로 시스템이 동작하는 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;어떤 사건이 발생하면 그 이벤트를 비동기적으로 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 장점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;확장성이 좋고, 고성능 애플리케이션에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스들이 직접 강하게 연결되지 않고 이벤트를 통해 느슨하게 연결될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 주요 구성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;시작 이벤트, 이벤트 브로커, 이벤트 프로세서, 처리 이벤트 등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;중재자 토폴로지와 브로커 토폴로지 같은 구조를 사용할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;11 마이크로서비스 아키텍처&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 마이크로서비스 아키텍처&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 핵심 목표&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;마이크로서비스의 주요 목표는 서비스 간 결합도를 낮추는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;각 서비스가 독립적으로 개발, 배포, 확장될 수 있도록 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 데이터 격리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;마이크로서비스는 서비스별로 데이터를 분리하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;데이터베이스를 공유하면 서비스 간 의존성이 커질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) API Gateway&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;클라이언트 요청을 여러 서비스로 라우팅하기 위해 API Gateway를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;인증, 인가, SSL, 캐싱, 라우팅 같은 공통 기능을 처리할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;12 DDD와 마이크로서비스 설계&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) DDD&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;DDD는 Domain Driven Design의 줄임말로 도메인 주도 설계를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;비즈니스 도메인을 중심으로 시스템을 설계하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) MSA와의 관계&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;MSA에서는 서비스를 비즈니스 기능 단위로 나누는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;DDD는 어떤 기준으로 서비스를 나눌지 판단하는 데 도움을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 서브도메인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 핵심 서브도메인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;기업의 경쟁력을 만드는 핵심 비즈니스 영역이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;직접 개발하고 집중적으로 관리해야 하는 영역이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 지원 서브도메인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;비즈니스에 필요하지만 핵심 경쟁력은 아닌 영역이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 일반 서브도메인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;비즈니스에 특화되지는 않았지만 필요한 영역이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;기존 제품이나 SaaS를 활용해 대체할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 바운디드 컨텍스트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;바운디드 컨텍스트는 하나의 도메인 모델이 적용되는 경계이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;같은 단어라도 컨텍스트가 다르면 의미가 달라질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 중요한 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스의 경계를 정할 때 바운디드 컨텍스트를 기준으로 삼을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;내부 응집도는 높이고, 외부 의존도는 낮추는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 유비쿼터스 언어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;유비쿼터스 언어는 특정 도메인 안에서 모두가 같은 의미로 사용하는 공통 언어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;기획자, 개발자, 사용자, 도메인 전문가가 같은 용어를 같은 의미로 사용하도록 돕는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 필요한 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;용어가 다르면 요구사항 이해가 달라질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;유비쿼터스 언어를 정리하면 도메인 이해와 커뮤니케이션 오류를 줄일 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;13 이벤트 스토밍&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 이벤트 스토밍의 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 이벤트 스토밍&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이벤트 스토밍은 이벤트를 중심으로 이해관계자들이 모여 도메인을 분석하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;최종 결과는 컨텍스트맵으로 이어질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 목적&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;시스템에서 어떤 사건이 발생하고, 누가 어떤 명령을 내리고, 어떤 데이터가 바뀌는지 시각적으로 정리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 주요 스티커 유형&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 도메인 이벤트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이미 발생한 사건이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;과거시제 동사로 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 커맨드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;도메인 이벤트를 발생시키는 명령이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;API 요청과 연결될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 액터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;시스템을 사용하는 사람이나 조직의 역할이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) 애그리게이트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;커맨드와 이벤트가 처리하는 데이터이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;상태가 변경되는 핵심 데이터로 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) 정책&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;특정 이벤트가 발생했을 때 어떤 커맨드를 실행할지 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&amp;ldquo;이 이벤트가 발생하면 이 명령을 수행한다&amp;rdquo;처럼 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(6) 핫스팟&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;아직 결정되지 않은 질문, 의문, 위험 요소를 표시한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;14 아키텍처 도식화와 C4 Model&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 아키텍처 도식화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 필요한 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;아키텍처는 말로만 설명하면 이해하기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;시스템 구조를 그림으로 표현하면 이해관계자와 개발자가 같은 구조를 공유하기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 도구&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;UML, C4, ArchiMate 같은 표준이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;PlantUML은 텍스트 기반으로 다이어그램을 작성할 수 있는 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) C4 Model&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Context&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;전체 시스템과 외부 사용자, 외부 시스템의 관계를 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Container&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;시스템 내부의 배포 가능한 단위를 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;웹 애플리케이션, API 서버, 데이터베이스 같은 단위가 컨테이너가 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) Component&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너 내부의 주요 모듈과 역할을 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) Code&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컴포넌트 내부의 클래스 구조를 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;필요할 때만 상세하게 작성한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;15 Spring Cloud&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Spring Cloud의 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Spring Cloud&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Spring Cloud는 마이크로서비스 아키텍처를 구축하고 관리하기 위한 도구와 프레임워크의 모음이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Spring Boot 기반 애플리케이션에 여러 분산 시스템 기능을 추가할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 주요 구성 요소&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Service Discovery&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스의 위치를 등록하고 찾는 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;대표적으로 Eureka가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) API Gateway&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;클라이언트와 마이크로서비스 사이에서 라우팅, 인증, 로드밸런싱 등을 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) Circuit Breaker&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;장애가 발생한 서비스 호출을 격리하여 전체 장애 확산을 막는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;과거에는 Hystrix를 사용했고, 현재는 Resilience4J를 많이 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) Configuration Management&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;여러 서비스의 설정 정보를 중앙에서 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) Distributed Tracing&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;여러 서비스를 거치는 요청 흐름을 추적한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;장애 분석과 성능 최적화에 도움이 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;16 Docker 기본 개념&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Docker&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Docker는 애플리케이션과 실행에 필요한 파일, 라이브러리, 설정을 컨테이너 형태로 패키징하고 실행하는 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) VM과 차이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;VM은 운영체제 전체를 가상화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Docker 컨테이너는 호스트의 커널을 공유하고, 애플리케이션 실행에 필요한 환경만 별도로 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 장점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;VM보다 가볍고 실행이 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;개발 환경과 운영 환경의 차이를 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 컨테이너&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너는 애플리케이션을 실행하기 위한 격리된 환경이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;애플리케이션, 라이브러리, 설정 파일을 함께 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 이미지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이미지는 컨테이너를 만들기 위한 실행 템플릿이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너는 이미지를 실행한 결과이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) Dockerfile&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Dockerfile은 이미지를 만들기 위한 명령어를 작성한 파일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;어떤 베이스 이미지를 사용할지, 어떤 파일을 복사할지, 어떤 명령으로 실행할지를 정의한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;17 Docker 주요 실습&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 기본 명령어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) docker -v&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Docker 버전을 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) docker run&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이미지를 기반으로 컨테이너를 생성하고 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) docker ps&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;현재 실행 중인 컨테이너 목록을 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) docker ps -a&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;종료된 컨테이너를 포함해 모든 컨테이너를 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) docker images&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;로컬에 저장된 이미지 목록을 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(6) docker rm&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너를 삭제한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(7) docker rmi&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이미지를 삭제한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 웹 서버 실습&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 포트 매핑&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너 내부의 80번 포트를 호스트의 80번 포트와 연결했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이를 통해 브라우저에서 컨테이너 내부 웹 서버에 접속할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Apache 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Ubuntu 컨테이너에 apache2를 설치하고 service apache2 start로 웹 서버를 실행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) WordPress 실습&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) MySQL 컨테이너&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;WordPress에서 사용할 DB로 MySQL 컨테이너를 실행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) WordPress 컨테이너&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;WordPress 컨테이너를 실행하고 MySQL 컨테이너와 연결했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) Volume 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;DB 데이터를 컨테이너 내부에만 저장하면 컨테이너 삭제 시 데이터가 사라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Volume을 사용하면 데이터를 호스트나 Docker Volume에 저장해 유지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) Docker Network&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) bridge&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;기본 네트워크 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너는 브리지 네트워크를 통해 외부와 통신한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) host&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너가 호스트의 네트워크를 그대로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) none&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;네트워크를 사용하지 않는 컨테이너를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) network alias&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;같은 네트워크 안에서 컨테이너를 별칭으로 접근할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) Docker Logging&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) json-file&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Docker의 기본 로그 드라이버이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너의 stdout, stderr 로그를 JSON 파일로 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) syslog&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;로그를 syslog로 보낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) fluentd&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;fluentd를 이용해 로그를 수집하고 MongoDB 같은 저장소로 보낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) CloudWatch&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;AWS 환경에서는 CloudWatch로 컨테이너 로그를 전송할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6) 이미지 관리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) docker commit&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;실행 중인 컨테이너의 상태를 이미지로 저장할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) docker tag&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이미지에 새로운 이름과 태그를 붙일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) docker push&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이미지를 Docker Hub나 Private Registry에 업로드할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) docker pull&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;원격 저장소에서 이미지를 내려받을 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;18 Docker Swarm&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Docker Swarm&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Docker Swarm은 여러 Docker 서버를 하나의 클러스터처럼 관리하는 오케스트레이션 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 필요한 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;실제 운영 환경에서는 컨테이너를 하나의 서버에서만 실행하기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;여러 서버에 컨테이너를 분산 배치하고, 장애 시 복구하고, 서비스를 확장해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 주요 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Manager Node&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;클러스터를 관리하는 노드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스 생성, 스케줄링, 상태 관리를 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Worker Node&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;실제 컨테이너 작업을 실행하는 노드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) Service&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Swarm에서 실행할 애플리케이션 단위이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;몇 개의 replica를 실행할지 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) Replica&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;동일한 서비스 인스턴스의 개수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;replica를 늘리면 여러 컨테이너가 분산 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) Swarm 실습&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 클러스터 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;manager 노드에서 docker swarm init을 실행해 클러스터를 생성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) worker join&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;worker 노드들은 join token을 사용해 클러스터에 참여했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) service create&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;docker service create 명령으로 서비스를 생성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) scale&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;docker service scale 명령으로 서비스 인스턴스 수를 늘리거나 줄였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) 자가복구&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너 하나를 강제로 삭제해도 Swarm이 원하는 replica 수를 유지하기 위해 새 컨테이너를 다시 생성한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;19 Kubernetes&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Kubernetes&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Kubernetes는 컨테이너 오케스트레이션 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;여러 서버에서 컨테이너를 배포, 확장, 복구, 네트워킹, 서비스 연결까지 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 필요한 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;컨테이너가 많아지면 수동으로 관리하기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;어느 서버에 어떤 컨테이너를 배치할지, 장애 시 어떻게 복구할지, 외부 요청을 어떻게 연결할지 자동화가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 시장 표준&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;여러 오케스트레이션 도구 중 Kubernetes가 사실상 시장 표준으로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) Kubernetes 구성 요소&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) kube-apiserver&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Kubernetes API를 제공하는 서버이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;모든 요청은 API Server를 통해 처리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) etcd&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;클러스터 상태와 설정 정보를 저장하는 key-value 저장소이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) kube-scheduler&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;새로 생성되는 Pod를 어떤 노드에 배치할지 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) kube-controller-manager&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;여러 컨트롤러를 실행하며 클러스터 상태를 원하는 상태로 유지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) kubelet&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;각 노드에서 실행되며, Pod와 컨테이너 상태를 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(6) kube-proxy&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Service 네트워크와 트래픽 전달을 담당한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;20 Kubernetes 주요 오브젝트&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Pod&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Pod는 Kubernetes에서 배포 가능한 가장 작은 실행 단위이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;하나 이상의 컨테이너를 포함할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) ReplicaSet&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;ReplicaSet은 정해진 수의 Pod가 항상 실행되도록 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Pod가 죽으면 새 Pod를 만들어 개수를 유지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) Deployment&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Deployment는 애플리케이션 배포 단위이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;내부적으로 ReplicaSet과 Pod를 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 사용하는 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;업데이트, 롤백, 스케일링을 쉽게 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) Service&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Service는 Pod에 접근하기 위한 고정된 네트워크 진입점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Pod는 생성되고 삭제되면서 IP가 바뀔 수 있기 때문에 Service가 안정적인 접근 경로를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) Service Type&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) ClusterIP&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;클러스터 내부에서만 접근 가능한 Service이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) NodePort&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;모든 노드의 특정 포트를 열어 외부에서 접근할 수 있게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) LoadBalancer&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;클라우드 제공자의 로드밸런서를 사용해 외부 IP를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6) Update와 Rollback&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Update&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Deployment의 이미지 버전을 바꿔 새로운 버전으로 배포할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Rollback&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;문제가 생기면 이전 버전으로 되돌릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7) Scaling&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;replicas 수를 조절해 Pod 개수를 늘리거나 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;트래픽이 많아지면 늘리고, 적어지면 줄일 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;21 Ingress와 Service Mesh&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Ingress&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Ingress는 외부 요청을 경로 기반이나 도메인 기반으로 내부 Service에 전달하기 위한 Kubernetes 객체이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 필요한 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;MSA에서는 /user, /product, /pay 같은 경로를 각각 다른 서비스로 보내야 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Ingress는 이런 라우팅 규칙을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) SSL/TLS 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;여러 서비스에 각각 인증서를 넣는 대신 Ingress에서 SSL/TLS를 일괄 처리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) Ingress Controller&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Ingress는 규칙만 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;실제로 요청을 받아 라우팅하는 주체는 Ingress Controller이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 예시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;nginx ingress controller를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;외부 요청은 Ingress Controller를 거쳐 내부 Service로 전달된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) Istio&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Istio는 마이크로서비스 간 통신을 관리하는 서비스 메쉬 플랫폼이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Sidecar&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Kubernetes에서는 Pod마다 Envoy Proxy를 sidecar로 삽입해 트래픽을 통제할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 기능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Istio는 라우팅, Circuit Breaker, fault injection, 버전별 트래픽 분배, 로그인 사용자 기반 라우팅 같은 기능을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) Kiali&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Kiali는 Istio 서비스 메쉬의 트래픽 흐름을 시각화해주는 도구이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;22 CI/CD&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) CI/CD의 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) CI&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;CI는 &lt;b&gt;Continuous Integration&lt;/b&gt;의 줄임말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;여러 개발자의 코드를 자주 통합하고 테스트하는 과정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) CD&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;CD는 Continuous Delivery 또는 Continuous Deployment를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;코드가 항상 배포 가능한 상태를 유지하거나, 실제 운영 환경까지 자동 배포되도록 만드는 과정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 핵심&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;CI/CD는 개발자의 코드가 사용자가 사용할 수 있는 서비스로 전달되는 과정을 자동화하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) Git 브랜치 전략&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Gitflow&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;master, develop, release, feature, hotfix 브랜치를 사용하는 전략이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;브랜치가 많아 관리가 복잡할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Trunk-based&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;main 또는 trunk 브랜치를 중심으로 짧은 주기의 통합을 지향한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;CI/CD와 잘 맞는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) Github Flow&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;main과 feature 브랜치를 중심으로 작업한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;main에 merge되면 배포로 이어지는 단순한 흐름을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) Github Actions&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Github Actions는 GitHub에서 제공하는 Workflow 자동화 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;테스트, 빌드, 배포 같은 작업을 자동화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Workflow&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;자동화 프로세스의 최상위 단위이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;.github/workflows 폴더 안에 YAML 파일로 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) Event&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Workflow를 실행시키는 조건이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;push, pull request, cron, webhook 등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) Job&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Workflow 안에서 실행되는 작업 단위이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;여러 Job은 병렬 또는 순차적으로 실행될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) Step&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Job 안에서 실행되는 세부 작업이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;명령어를 실행하거나 Action을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(6) Runner&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Workflow가 실제로 실행되는 환경이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;GitHub가 제공하는 runner를 사용할 수도 있고, 직접 runner를 구성할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) Spring Boot와 CI/CD&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Spring Boot&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Spring Boot는 Spring 기반 애플리케이션을 빠르게 시작할 수 있도록 도와주는 프레임워크이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;내장 Tomcat을 제공하므로 별도의 WAS 설정 없이 실행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Gradle 빌드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;gradlew build를 통해 jar 파일을 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;결과물은 build/libs 아래에 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) Docker 이미지 빌드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Dockerfile을 작성해 Spring Boot jar 파일을 컨테이너 이미지로 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) Kubernetes 배포&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Deployment와 Service YAML을 작성해 Kubernetes 클러스터에 배포할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;GitHub Actions를 이용하면 빌드부터 배포까지 자동화할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;23 학습 내용 정리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) MSA&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) MSA는 큰 애플리케이션을 작은 서비스로 나누는 아키텍처이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 서비스는 비즈니스 기능 단위로 나누는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 각 서비스는 독립 실행, 독립 배포, 독립 확장이 가능해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) MSA는 장점도 크지만 운영 복잡도도 크기 때문에 무조건 선택하면 안 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) MSA 설계&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) DDD는 마이크로서비스 경계를 나누는 데 도움을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 바운디드 컨텍스트는 서비스 경계를 정의할 때 중요한 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 유비쿼터스 언어는 도메인 안에서 같은 용어를 같은 의미로 사용하게 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) 이벤트 스토밍은 도메인 이벤트를 중심으로 서비스를 도출하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 아키텍처 문서화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) ADR은 중요한 아키텍처 결정을 기록하는 문서이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) C4 Model은 Context, Container, Component, Code 단계로 아키텍처를 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) PlantUML은 텍스트로 다이어그램을 작성할 수 있는 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) Spring Cloud&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Spring Cloud는 Spring Boot 기반 MSA 구축을 도와주는 도구 모음이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Eureka는 서비스 등록과 탐색을 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) Gateway는 요청 라우팅과 인증, 필터링을 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) Resilience4J는 장애 격리를 위한 Circuit Breaker 기능을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) Config는 설정 정보를 중앙에서 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) Docker&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Docker는 애플리케이션 실행 환경을 컨테이너로 패키징한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) 이미지는 컨테이너 실행을 위한 템플릿이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 컨테이너는 이미지를 실행한 결과이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) Volume은 컨테이너 데이터 유지에 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) Dockerfile은 이미지를 만들기 위한 설계도이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6) Docker Swarm&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Docker Swarm은 여러 Docker 서버를 클러스터로 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) manager node와 worker node로 구성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) service와 replica를 통해 컨테이너를 분산 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) 컨테이너가 죽어도 원하는 상태를 유지하기 위해 자가복구한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7) Kubernetes&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) Kubernetes는 컨테이너 오케스트레이션 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) Pod는 가장 작은 배포 단위이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) Deployment는 애플리케이션 배포와 업데이트를 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) Service는 Pod에 안정적으로 접근하기 위한 네트워크 객체이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) Ingress는 외부 요청을 경로 또는 도메인 기준으로 내부 서비스에 연결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8) CI/CD&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) CI는 코드를 지속적으로 통합하고 테스트하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) CD는 배포 가능한 상태를 유지하거나 배포 자체를 자동화하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) GitHub Actions는 Workflow를 통해 빌드, 테스트, 배포를 자동화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) Spring Boot 애플리케이션은 Gradle로 빌드하고, Docker 이미지로 만들고, Kubernetes에 배포할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9) 이틀 동안 배운 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(1) MSA는 단순히 서비스를 작게 나누는 것이 아니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스를 나누는 기준은 기술 계층이 아니라 비즈니스 도메인이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;잘못 나누면 오히려 복잡도만 증가할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(2) MSA는 설계와 운영이 함께 필요하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스 분리만으로 MSA가 완성되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스 검색, 설정 관리, 장애 격리, 로그, 모니터링, 배포 자동화가 함께 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(3) 컨테이너는 MSA 운영의 기본 기술이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Docker는 애플리케이션 실행 환경을 컨테이너로 통일해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;Kubernetes는 여러 컨테이너를 실제 운영 환경에서 관리할 수 있게 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(4) 아키텍처 결정은 기록해야 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;어떤 기술을 선택했는지, 왜 그렇게 나누었는지 기록하지 않으면 나중에 유지보수가 어려워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;ADR과 C4 Model은 이런 결정을 정리하고 공유하는 데 도움이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(5) CI/CD는 MSA에서 필수에 가깝다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;서비스가 많아질수록 수동 배포는 현실적으로 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;GitHub Actions 같은 도구를 이용해 빌드, 테스트, 이미지 생성, 배포를 자동화해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;(6) 앞으로의 학습 방향&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;이번 특강을 통해 MSA, Docker, Kubernetes, CI/CD가 서로 따로 떨어진 기술이 아니라 하나의 흐름으로 연결된다는 것을 알게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;앞으로&lt;/span&gt; Spring Boot&lt;span&gt;로&lt;/span&gt; &lt;span&gt;마이크로서비스를&lt;/span&gt; &lt;span&gt;만들고&lt;/span&gt;, Docker &lt;span&gt;이미지로&lt;/span&gt; &lt;span&gt;패키징한&lt;/span&gt; &lt;span&gt;뒤&lt;/span&gt;, Kubernetes&lt;span&gt;에&lt;/span&gt; &lt;span&gt;배포하는&lt;/span&gt; &lt;span&gt;과정을&lt;/span&gt; &lt;span&gt;직접&lt;/span&gt; &lt;span&gt;실습해보면&lt;/span&gt; MSA &lt;span&gt;구조를&lt;/span&gt; &lt;span&gt;더&lt;/span&gt; &lt;span&gt;명확히&lt;/span&gt; &lt;span&gt;이해할&lt;/span&gt; &lt;span&gt;수&lt;/span&gt; &lt;span&gt;있을&lt;/span&gt; &lt;span&gt;것&lt;/span&gt; &lt;span&gt;같다&lt;/span&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>멀티캠퍼스</category>
      <category>[현대이지웰] Java 풀스택 개발자 아카데미 8회차</category>
      <category>멀티캠퍼스부트캠프</category>
      <category>부트캠프</category>
      <author>buckwheat</author>
      <guid isPermaLink="true">https://buckwheat0.tistory.com/73</guid>
      <comments>https://buckwheat0.tistory.com/73#entry73comment</comments>
      <pubDate>Tue, 30 Jun 2026 17:25:38 +0900</pubDate>
    </item>
    <item>
      <title>[2026.06.24] - TIL 58일차 개발자를 위한 UI/UX 특강 정리</title>
      <link>https://buckwheat0.tistory.com/71</link>
      <description>&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;목차&lt;br /&gt;1 오늘 학습 흐름&lt;br /&gt;2 UI/UX 특강 개요&lt;br /&gt;3 UI와 UX의 차이&lt;br /&gt;4 페르소나&lt;br /&gt;5 고객 여정 지도&lt;br /&gt;6 사이트맵&lt;br /&gt;7 와이어프레임&lt;br /&gt;8 프로토타입&lt;br /&gt;9 CodeMate 서비스 기획&lt;br /&gt;10 고객 여정 지도 설계 내용&lt;br /&gt;11 사이트맵 설계 내용&lt;br /&gt;12 Figma 프로토타입 제작 및 제출&lt;br /&gt;13 오늘 학습한 핵심 정리&lt;/blockquote&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1 오늘 학습 흐름&lt;/p&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) 개발자를 위한 UI/UX 특강

    (1) 오늘 학습 내용
    오늘은 개발자를 위한 UI/UX 특강을 들었다.
    단순히 화면을 예쁘게 만드는 것이 아니라, 사용자의 문제를 이해하고 그 문제를 해결하는 서비스 구조를 설계하는 과정을 학습했다.

    (2) 실습 흐름
    오늘 실습은 페르소나 작성, 고객 여정 지도 작성, 사이트맵 설계, 와이어프레임 제작, 프로토타입 제작 및 링크 제출 순서로 진행되었다.

    (3) 핵심 목표
    오늘의 핵심은 사용자의 문제를 먼저 파악하고, 그 사용자가 서비스를 이용하는 흐름에 맞춰 기능과 화면 구조를 설계하는 것이다.

    (4) 오늘 만든 서비스
    나는 초보 개발자 학습 관리 모바일 앱인 CodeMate를 기획했다.
    CodeMate는 개발 공부를 시작한 초보자가 개념 정리, 실습 코드, 에러 해결 기록, 복습을 한곳에서 관리할 수 있도록 돕는 서비스이다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2 UI/UX 특강 개요&lt;/p&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) UI/UX의 필요성

    (1) 개발자에게 UI/UX가 필요한 이유
    개발자는 기능 구현에 집중하기 쉽다.
    하지만 실제 사용자는 기능이 존재하는 것뿐만 아니라, 그 기능을 얼마나 쉽게 찾고 사용할 수 있는지를 중요하게 느낀다.

    (2) 좋은 서비스의 기준
    좋은 서비스는 단순히 기능이 많은 서비스가 아니다.
    사용자의 문제를 정확히 해결하고, 사용자가 헷갈리지 않게 자연스러운 흐름을 제공하는 서비스가 좋은 서비스이다.

    (3) 오늘 특강의 의미
    오늘 특강을 통해 개발자는 코드를 작성하기 전에 사용자의 상황, 감정, 행동, 문제점을 먼저 이해해야 한다는 것을 배웠다.
    즉, 개발은 기능 구현에서 시작되는 것이 아니라 사용자 이해에서 시작된다는 점을 알 수 있었다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3 UI와 UX의 차이&lt;/p&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) UI

    (1) UI의 의미
    UI는 User Interface의 줄임말이다.
    사용자가 서비스를 사용할 때 직접 보고 클릭하는 화면 요소를 의미한다.

    (2) UI 요소
    버튼, 메뉴, 입력창, 아이콘, 색상, 폰트, 레이아웃 등이 UI에 해당한다.
    사용자는 UI를 통해 서비스와 상호작용한다.

    (3) UI의 핵심
    UI는 사용자가 기능을 쉽게 찾고 사용할 수 있도록 화면을 구성하는 것이다.
    보기 좋은 디자인도 중요하지만, 사용하기 쉬운 구조가 더 중요하다.

2) UX

    (1) UX의 의미
    UX는 User Experience의 줄임말이다.
    사용자가 서비스를 이용하면서 느끼는 전체 경험을 의미한다.

    (2) UX의 범위
    UX는 화면 디자인뿐만 아니라 사용자의 감정, 행동 흐름, 불편함, 만족감까지 포함한다.
    사용자가 서비스를 처음 발견하고, 가입하고, 기능을 사용하고, 다시 돌아오는 전체 과정이 UX에 해당한다.

    (3) UX의 핵심
    UX는 사용자가 원하는 목표를 편하고 자연스럽게 달성할 수 있도록 만드는 것이다.
    사용자가 중간에 막히거나 헷갈리지 않도록 흐름을 설계해야 한다.

3) UI와 UX의 관계

    (1) UI는 UX의 일부이다
    UI는 사용자가 직접 만나는 화면이고, UX는 그 화면을 포함한 전체 경험이다.
    좋은 UI는 좋은 UX를 만드는 데 중요한 역할을 한다.

    (2) 예시
    버튼이 예쁘게 생겼더라도 사용자가 어디를 눌러야 할지 모르면 좋은 UX라고 할 수 없다.
    반대로 화면이 단순하더라도 사용자가 원하는 기능을 빠르게 찾고 사용할 수 있다면 좋은 UX가 될 수 있다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4 페르소나&lt;/p&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) 페르소나의 의미

    (1) 페르소나
    페르소나는 서비스를 사용할 대표 사용자를 구체적인 인물처럼 설정한 것이다.
    실제 사용자를 상상하기 쉽게 이름, 상황, 목표, 문제점 등을 정리한다.

    (2) 페르소나를 만드는 이유
    모든 사용자를 막연하게 생각하면 서비스 방향이 흐려질 수 있다.
    특정 사용자를 구체적으로 설정하면 그 사람이 어떤 기능을 필요로 하는지 더 명확하게 알 수 있다.

    (3) 개발자 관점에서의 의미
    개발자는 기능 중심으로 생각하기 쉽지만, 페르소나를 만들면 사용자 중심으로 사고할 수 있다.
    &amp;ldquo;이 기능이 필요한가?&amp;rdquo;보다 &amp;ldquo;이 사용자가 이 기능을 왜 필요로 하는가?&amp;rdquo;를 생각하게 된다.

2) 오늘 설정한 페르소나

    (1) 페르소나 이름
    오늘 설계한 CodeMate의 페르소나는 초보 개발자 현우이다.

    (2) 페르소나 상황
    현우는 개발 공부를 막 시작한 입문자이다.
    실습 중 에러가 자주 발생하고, 해결 방법을 검색해서 해결하더라도 나중에 다시 기억하지 못하는 문제가 있다.

    (3) 페르소나 문제
    현우는 에러 원인을 파악하기 어렵고, 공부한 내용을 체계적으로 정리하기 힘들어한다.
    또한 개념 정리, 실습 코드, 에러 해결 과정을 따로 관리하다 보니 복습이 어렵다.

    (4) 페르소나 목표
    현우는 자신이 배운 개념, 실습 기록, 에러 해결 방법을 한곳에 정리하고 싶어 한다.
    나중에 같은 문제가 발생했을 때 빠르게 검색하고 다시 복습할 수 있는 서비스를 원한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5 고객 여정 지도&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;917&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIjoZm/dJMcadJa0Fw/OKM1ALo3EQzHGpAk2olb6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIjoZm/dJMcadJa0Fw/OKM1ALo3EQzHGpAk2olb6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIjoZm/dJMcadJa0Fw/OKM1ALo3EQzHGpAk2olb6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIjoZm%2FdJMcadJa0Fw%2FOKM1ALo3EQzHGpAk2olb6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1716&quot; height=&quot;917&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;917&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) 고객 여정 지도의 의미

    (1) 고객 여정 지도
    고객 여정 지도는 사용자가 서비스를 이용하는 전체 과정을 단계별로 정리한 것이다.
    사용자가 어떤 행동을 하고, 어떤 생각을 하며, 어떤 불편함을 느끼는지 한눈에 볼 수 있게 만든다.

    (2) 구성 요소
    고객 여정 지도에는 단계, 행동, 생각, 접점, 문제점, 개선 기회 등이 들어간다.

    (3) 사용하는 이유
    고객 여정 지도를 만들면 사용자가 어디에서 불편함을 느끼는지 알 수 있다.
    그리고 그 불편함을 해결하기 위해 어떤 기능이 필요한지 도출할 수 있다.

2) 오늘 만든 고객 여정 단계

    (1) 1단계 문제 인식
    사용자는 실습 중 에러를 만나고, 원인을 파악하지 못해 어려움을 느낀다.
    해결 방법을 검색하지만 어떤 자료가 정확한지 판단하기 어렵다.

    (2) 2단계 서비스 탐색
    사용자는 개발 공부 기록 서비스를 검색하고 여러 서비스를 비교한다.
    개념과 에러를 함께 정리할 수 있는 서비스가 필요하다고 느낀다.

    (3) 3단계 가입 및 첫 사용
    사용자는 회원가입을 하고 과목별 카테고리를 만든다.
    처음에는 기능이 많아 어디서부터 써야 할지 고민할 수 있다.

    (4) 4단계 학습 기록
    사용자는 오늘 배운 개념, 실습 코드, 에러와 해결 방법을 기록한다.
    기록을 저장하면서 나중에 다시 복습할 수 있다는 안정감을 느낀다.

    (5) 5단계 복습 및 지속 사용
    사용자는 이전 기록을 검색하고 복습 알림을 확인한다.
    자신의 학습 진도와 약점을 확인하면서 지속적으로 학습을 관리한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6 사이트맵&lt;/p&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) 사이트맵의 의미

    (1) 사이트맵
    사이트맵은 서비스의 전체 메뉴 구조를 정리한 지도이다.
    사용자가 어떤 메뉴를 통해 어떤 기능으로 이동할 수 있는지 보여준다.

    (2) 필요한 이유
    사이트맵을 만들면 서비스의 정보 구조를 먼저 정리할 수 있다.
    화면을 만들기 전에 어떤 기능이 어디에 위치해야 하는지 정할 수 있다.

    (3) 개발자 관점에서의 의미
    사이트맵은 나중에 페이지 구조, URL 설계, Controller 설계와도 연결될 수 있다.
    즉, UI/UX 설계뿐만 아니라 실제 개발 구조를 잡는 데도 도움이 된다.

2) CodeMate 사이트맵 구조

    (1) 홈
    홈은 서비스의 시작점이다.
    사용자는 홈에서 주요 기능으로 이동할 수 있다.

    (2) 대시보드
    대시보드에서는 학습 현황 요약, 최근 학습 기록, 복습 알림, 진도 통계, 약점 분석 요약을 확인할 수 있다.
    사용자가 현재 자신의 학습 상태를 한눈에 파악하는 공간이다.

    (3) 과목 관리
    과목 관리에서는 과목 목록, 과목 추가, 과목별 설정, 카테고리와 태그 관리를 할 수 있다.
    초보 개발자가 Java, Spring, SQL처럼 과목별로 학습 내용을 정리할 수 있게 돕는다.

    (4) 학습 기록
    학습 기록은 개념 정리와 실습 기록으로 나누었다.
    개념 목록, 개념 작성, 개념 상세 보기와 실습 목록, 실습 작성, 코드 저장, 파일 첨부, 실습 상세 보기 기능을 포함한다.

    (5) 에러 기록
    에러 기록에서는 에러 목록, 에러 작성, 에러 상세 보기, 해결 방법 정리, 관련 실습과 개념 연결 기능을 제공한다.
    초보 개발자가 같은 에러를 반복해서 검색하지 않도록 돕는 핵심 메뉴이다.

    (6) 복습 관리
    복습 관리에서는 복습 목록, 복습 계획 설정, 복습 알림 설정, 복습 진행, 복습 완료 기록을 관리한다.
    기록한 내용을 실제 학습 성과로 연결하기 위한 기능이다.

    (7) 검색
    검색 메뉴에서는 통합 검색, 개념 검색, 에러 검색, 코드 검색, 태그 검색을 제공한다.
    사용자가 과거 기록을 빠르게 찾을 수 있도록 돕는다.

    (8) 마이페이지
    마이페이지에서는 프로필 관리, 학습 목표 설정, 알림 설정, 데이터 백업과 내보내기, 로그아웃 기능을 제공한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7 와이어프레임&lt;/p&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) 와이어프레임의 의미

    (1) 와이어프레임
    와이어프레임은 실제 디자인을 하기 전에 화면의 구조를 간단하게 설계한 것이다.
    색상이나 세부 디자인보다 버튼, 메뉴, 콘텐츠 위치를 먼저 정리한다.

    (2) 필요한 이유
    와이어프레임을 만들면 화면에 어떤 정보가 들어가야 하는지 미리 확인할 수 있다.
    개발 전에 화면 흐름을 점검할 수 있어 불필요한 수정도 줄일 수 있다.

    (3) 개발자 관점에서의 의미
    와이어프레임은 프론트엔드 구현 전에 화면 구조를 이해하는 데 도움이 된다.
    어떤 컴포넌트가 필요한지, 어떤 데이터가 화면에 표시되어야 하는지 미리 파악할 수 있다.

2) CodeMate 와이어프레임 설계 방향

    (1) 주요 화면 설계
    고객 여정 지도와 사이트맵을 바탕으로 주요 화면 구조를 설계했다.
    대시보드, 학습 기록, 에러 기록, 복습 관리, 검색, 마이페이지가 핵심 화면이 된다.

    (2) 화면 설계 기준
    초보 개발자가 처음 사용해도 헷갈리지 않도록 메뉴를 명확하게 나누는 것이 중요하다고 생각했다.
    특히 에러 기록과 학습 기록을 분리하면서도 서로 연결될 수 있도록 설계했다.

    (3) 핵심
    와이어프레임은 예쁜 화면을 만드는 단계가 아니라, 사용자가 기능을 어떻게 찾고 사용할지 구조를 잡는 단계이다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8 프로토타입&lt;/p&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) 프로토타입의 의미

    (1) 프로토타입
    프로토타입은 실제 서비스처럼 화면을 클릭하고 이동해볼 수 있도록 만든 시안이다.
    완성된 서비스는 아니지만, 사용자 흐름을 미리 체험할 수 있다.

    (2) 필요한 이유
    프로토타입을 만들면 화면 이동이 자연스러운지, 사용자가 기능을 쉽게 찾을 수 있는지 확인할 수 있다.
    개발 전에 문제점을 발견하고 수정할 수 있다는 장점이 있다.

    (3) 오늘 제출 내용
    오늘은 Figma Make를 활용해 CodeMate 모바일 앱 디자인 프로토타입을 제작하고 링크를 제출했다.
    이를 통해 기획 내용을 단순 문서로만 정리하는 것이 아니라 실제 앱 화면 흐름에 가깝게 표현해보았다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9 CodeMate 서비스 기획&lt;/p&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) CodeMate

    (1) 서비스 이름
    오늘 기획한 앱 이름은 CodeMate이다.
    CodeMate는 코딩 공부를 함께 도와주는 친구라는 의미를 담은 이름이다.

    (2) 서비스 목적
    CodeMate는 초보 개발자가 공부한 개념, 실습 코드, 에러 해결 과정을 한곳에 기록하고 관리할 수 있도록 돕는 모바일 앱이다.

    (3) 주요 사용자
    주요 사용자는 개발 공부를 시작한 입문자이다.
    실습 중 에러를 자주 만나고, 개념 정리와 복습에 어려움을 느끼는 사용자를 대상으로 한다.

    (4) 해결하려는 문제
    초보 개발자는 에러가 발생했을 때 원인을 바로 파악하기 어렵다.
    또한 해결하더라도 기록하지 않으면 같은 문제를 반복해서 검색하게 된다.
    CodeMate는 그런 문제를 줄이고, 학습 기록을 복습 가능한 자산으로 만들기 위해 설계했다.

2) 주요 기능

    (1) 학습 기록
    사용자가 배운 개념과 실습 내용을 기록할 수 있다.

    (2) 에러 기록
    에러 메시지, 원인, 해결 방법을 기록할 수 있다.

    (3) 코드 저장
    실습 코드나 중요한 코드 조각을 저장할 수 있다.

    (4) 복습 관리
    기록한 내용을 다시 복습할 수 있도록 알림과 복습 목록을 제공한다.

    (5) 검색
    개념, 에러, 코드, 태그를 기준으로 이전 기록을 검색할 수 있다.

    (6) 대시보드
    학습 현황, 최근 기록, 복습 알림, 진도 통계, 약점 분석을 한눈에 보여준다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10 고객 여정 지도 설계 내용&lt;/p&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) 문제 인식 단계

    (1) 행동
    사용자는 수업 후 혼자 실습을 진행한다.
    실습 중 에러가 발생하면 에러 메시지를 확인하고 인터넷 검색이나 질문을 통해 해결하려고 한다.

    (2) 생각
    사용자는 왜 에러가 나는지 모르겠다고 느낀다.
    같은 에러를 또 만나면 어떻게 해야 할지 걱정한다.

    (3) 문제점
    에러 원인을 파악하기 어렵다.
    해결 방법을 찾아도 금방 잊어버린다.
    공부한 내용을 체계적으로 정리하기 힘들다.

    (4) 개선 기회
    에러 메시지 자동 저장 기능, 자주 발생하는 에러 가이드, 해결 방법 기록 UX가 필요하다.

2) 서비스 탐색 단계

    (1) 행동
    사용자는 개발 공부 기록 서비스를 검색한다.
    여러 서비스를 비교하고 리뷰와 기능을 확인한다.

    (2) 생각
    사용자는 개념과 에러를 함께 정리하고 싶다고 느낀다.
    개발 공부에 특화된 서비스가 필요하다고 생각한다.

    (3) 문제점
    일반 메모 앱은 개발 공부를 정리하기에 불편하다.
    어떤 서비스를 선택해야 할지 고민된다.

    (4) 개선 기회
    개발 과목별 템플릿, 실습 사용자 후기, 검색 최적화와 기능 비교 페이지를 제공할 수 있다.

3) 가입 및 첫 사용 단계

    (1) 행동
    사용자는 회원가입을 하고 과목별 카테고리를 만든다.
    기본 기능을 둘러본다.

    (2) 생각
    사용자는 과목별로 정리하니 편하다고 느낄 수 있다.
    하지만 처음에는 어떻게 써야 할지 모를 수 있다.

    (3) 문제점
    처음 사용자가 무엇을 적어야 할지 모른다.
    기능이 많아 초반에 복잡하게 느껴질 수 있다.

    (4) 개선 기회
    온보딩 튜토리얼, 초보자용 작성 예시, 카테고리 추천 기능이 필요하다.

4) 학습 기록 단계

    (1) 행동
    사용자는 오늘 배운 개념을 정리한다.
    실습 코드를 저장하고, 에러와 해결 방법을 기록한다.

    (2) 생각
    사용자는 나중에 다시 보면 도움이 되겠다고 느낀다.
    코드를 함께 저장하니 이해가 잘 된다고 느낀다.

    (3) 문제점
    기록이 많아지면 찾기 어렵다.
    코드와 설명을 따로 관리하면 불편하다.
    에러 기록 양식이 없으면 정리하기 힘들다.

    (4) 개선 기회
    태그, 즐겨찾기, 폴더 기능을 제공할 수 있다.
    코드와 설명 동시 저장 UI, 에러 기록 입력 가이드도 필요하다.

5) 복습 및 지속 사용 단계

    (1) 행동
    사용자는 이전 기록을 검색해 복습한다.
    복습 알림을 확인하고 학습 진도와 약점을 확인한다.

    (2) 생각
    사용자는 전에 정리한 내용을 바로 찾을 수 있어 편하다고 느낀다.
    자신의 약한 부분을 확인하고 스스로 문제를 해결할 수 있다고 느낀다.

    (3) 문제점
    복습할 내용을 직접 기억해야 하면 부담스럽다.
    어떤 부분이 약한지 파악하기 어렵다.
    꾸준히 사용하지 않으면 기록이 쌓이지 않는다.

    (4) 개선 기회
    복습 알림과 스페이스드 리피티션을 적용할 수 있다.
    학습 진도 대시보드, 약점 분석, 성취감 요소를 제공하면 지속 사용에 도움이 된다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;11 사이트맵 설계 내용&lt;/p&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) 전체 메뉴 구조

    (1) 홈
    홈은 전체 서비스의 시작 지점이다.
    사용자는 홈에서 대시보드, 과목 관리, 학습 기록, 에러 기록, 복습 관리, 검색, 마이페이지로 이동할 수 있다.

    (2) 대시보드
    대시보드는 사용자의 학습 상태를 요약해서 보여준다.
    학습 현황 요약, 최근 학습 기록, 복습 알림, 진도 통계, 약점 분석 요약 기능이 포함된다.

    (3) 과목 관리
    과목 관리는 학습 내용을 과목별로 분류하기 위한 메뉴이다.
    과목 목록, 과목 추가, 과목별 설정, 카테고리와 태그 관리 기능이 있다.

    (4) 학습 기록
    학습 기록은 개념 정리와 실습 기록으로 나뉜다.
    개념 목록, 개념 작성, 개념 상세 보기와 실습 목록, 실습 작성, 코드 저장, 파일 첨부, 실습 상세 보기 기능을 포함한다.

    (5) 에러 기록
    에러 기록은 개발자가 실습 중 만난 문제를 정리하는 메뉴이다.
    에러 목록, 에러 작성, 에러 상세 보기, 해결 방법 정리, 관련 실습과 개념 연결 기능을 제공한다.

    (6) 복습 관리
    복습 관리는 기록한 내용을 다시 학습하도록 돕는 메뉴이다.
    복습 목록, 복습 계획 설정, 복습 알림 설정, 복습 진행, 복습 완료 기록 기능이 있다.

    (7) 검색
    검색은 쌓인 기록을 빠르게 찾기 위한 메뉴이다.
    통합 검색, 개념 검색, 에러 검색, 코드 검색, 태그 검색 기능이 포함된다.

    (8) 마이페이지
    마이페이지는 개인 설정을 관리하는 메뉴이다.
    프로필 관리, 학습 목표 설정, 알림 설정, 데이터 백업과 내보내기, 로그아웃 기능을 제공한다.

2) 사이트맵 설계 핵심

    (1) 고객 여정과 연결
    사이트맵은 고객 여정 단계와 연결되도록 설계했다.
    문제 인식 단계에서는 홈과 대시보드, 서비스 탐색 단계에서는 기능 소개, 가입 및 첫 사용 단계에서는 과목 관리와 마이페이지가 연결된다.
    학습 기록 단계에서는 학습 기록과 에러 기록, 복습 단계에서는 복습 관리와 검색이 중심이 된다.

    (2) 기능 분류
    기능을 단순히 많이 넣는 것이 아니라 사용자의 흐름에 맞게 분류했다.
    학습을 시작하고, 기록하고, 다시 찾고, 복습하는 흐름이 자연스럽게 이어지도록 구성했다.

    (3) 설계 핵심 포인트
    초보 개발자의 학습 흐름인 문제 인식, 탐색, 사용, 기록, 복습에 맞춰 메뉴 구조를 구성했다.
    학습 기록과 에러 기록을 중심 기능으로 배치하고, 복습과 검색 기능을 강화했다.
    대시보드에서 학습 현황을 한눈에 파악할 수 있도록 설계했다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;12 Figma 프로토타입 제작 및 제출&lt;/p&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) Figma Make 활용

    (1) Figma Make
    오늘은 Figma Make를 활용해 CodeMate 모바일 앱 디자인을 제작했다.
    텍스트로 서비스의 목적과 화면 구성을 입력하고, 이를 바탕으로 모바일 앱 화면을 생성했다.

    (2) 모바일 앱 디자인
    CodeMate는 모바일 앱 형태로 설계했다.
    초보 개발자가 수업 중이나 실습 중에도 빠르게 기록하고 다시 찾아볼 수 있도록 모바일 접근성을 고려했다.

    (3) 프로토타입 제출
    최종적으로 Figma 프로토타입 링크를 제출했다.

    제출 링크:
    https://www.figma.com/make/Nky04gDXffrrrjs8T3gaks/CodeMate-Mobile-App-Design?code-node-id=0-9&amp;amp;p=f&amp;amp;t=OKhu83fVdf9OX1nS-0&amp;amp;fullscreen=1

2) 프로토타입 제작의 의미

    (1) 기획을 화면으로 구체화
    고객 여정 지도와 사이트맵은 사용자의 흐름과 기능 구조를 정리하는 단계이다.
    프로토타입은 이 구조를 실제 화면처럼 볼 수 있게 만드는 단계이다.

    (2) 사용자 흐름 확인
    프로토타입을 통해 사용자가 홈에서 대시보드, 학습 기록, 에러 기록, 복습 관리로 이동하는 흐름을 확인할 수 있다.
    화면 간 연결이 자연스러운지 점검할 수 있다는 점에서 의미가 있었다.

    (3) 개발 전 검증
    프로토타입을 먼저 만들면 실제 개발 전에 화면 구조와 기능 흐름을 검토할 수 있다.
    개발 후 수정하는 것보다 기획 단계에서 문제를 발견하고 수정하는 것이 훨씬 효율적이다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;13 오늘 학습한 핵심 정리&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;1) 페르소나

    (1) 페르소나는 대표 사용자를 구체화하는 과정이다.
    (2) 사용자의 상황, 목표, 문제점을 정리해 서비스 방향을 잡는다.
    (3) 오늘은 에러 앞에서 멈추는 초보 개발자 현우를 페르소나로 설정했다.

2) 고객 여정 지도

    (1) 고객 여정 지도는 사용자가 서비스를 이용하는 전체 과정을 단계별로 정리한 것이다.
    (2) 행동, 생각, 접점, 문제점, 개선 기회를 함께 정리한다.
    (3) 사용자가 어느 지점에서 불편을 느끼는지 파악할 수 있다.

3) 사이트맵

    (1) 사이트맵은 서비스의 전체 메뉴 구조를 정리한 것이다.
    (2) 사용자가 어떤 메뉴를 통해 어떤 기능으로 이동하는지 보여준다.
    (3) 개발 관점에서는 페이지 구조와 기능 구조를 잡는 데 도움이 된다.

4) 와이어프레임

    (1) 와이어프레임은 화면의 기본 구조를 설계하는 단계이다.
    (2) 색상이나 디자인보다 메뉴, 버튼, 콘텐츠 배치를 먼저 정리한다.
    (3) 개발 전에 화면 흐름과 필요한 기능을 확인할 수 있다.

5) 프로토타입

    (1) 프로토타입은 실제 서비스처럼 화면 이동을 체험할 수 있는 시안이다.
    (2) 개발 전에 사용 흐름을 검증할 수 있다.
    (3) 오늘은 Figma Make를 활용해 CodeMate 모바일 앱 프로토타입 링크를 제출했다.

6) CodeMate

    (1) CodeMate는 초보 개발자를 위한 학습 관리 앱이다.
    (2) 개념 정리, 실습 코드, 에러 기록, 복습 관리를 핵심 기능으로 설계했다.
    (3) 사용자가 같은 에러를 반복해서 검색하지 않고, 자신의 기록을 학습 자산으로 만들 수 있도록 기획했다.

7) 오늘 배운 점

    (1) UI/UX는 디자인만의 문제가 아니다
    오늘 특강을 통해 UI/UX는 단순히 화면을 예쁘게 만드는 것이 아니라 사용자의 문제를 해결하는 과정이라는 것을 알게 되었다.

    (2) 개발 전 사용자 이해가 중요하다
    기능을 만들기 전에 사용자가 어떤 상황에서 어떤 문제를 겪는지 먼저 파악해야 한다.
    페르소나와 고객 여정 지도는 그 과정을 도와주는 도구이다.

    (3) 사이트맵은 개발 구조와도 연결된다
    사이트맵을 만들면서 메뉴 구조가 곧 페이지 구조와 기능 구조로 이어질 수 있다는 것을 알게 되었다.
    이는 나중에 실제 웹 개발을 할 때 Controller, URL, View 설계와도 연결될 수 있다.

    (4) 초보 개발자 서비스의 핵심은 기록과 복습이다
    초보 개발자는 에러를 해결해도 다시 잊어버리기 쉽다.
    그래서 단순 기록 기능뿐만 아니라 검색, 복습 알림, 대시보드, 약점 분석 기능이 중요하다고 생각했다.

    (5) Figma 프로토타입을 통해 기획이 더 구체화되었다
    처음에는 막연히 개발 공부를 도와주는 서비스라고 생각했지만, 페르소나, 고객 여정 지도, 사이트맵, 와이어프레임을 거치면서 필요한 기능과 화면 구조가 구체화되었다.
    마지막으로 Figma Make를 활용해 CodeMate 모바일 앱 프로토타입을 만들고 제출하면서 아이디어가 실제 서비스 화면 흐름으로 이어지는 과정을 경험할 수 있었다.&lt;/code&gt;&lt;/pre&gt;</description>
      <category>멀티캠퍼스</category>
      <category>[현대이지웰] Java 풀스택 개발자 아카데미 8회차</category>
      <category>멀티캠퍼스부트캠프</category>
      <category>부트캠프</category>
      <author>buckwheat</author>
      <guid isPermaLink="true">https://buckwheat0.tistory.com/71</guid>
      <comments>https://buckwheat0.tistory.com/71#entry71comment</comments>
      <pubDate>Thu, 25 Jun 2026 03:29:12 +0900</pubDate>
    </item>
    <item>
      <title>[2026.06.23] - TIL 57일차(Spring MVC03 게시판 프로젝트 완성)</title>
      <link>https://buckwheat0.tistory.com/70</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;목차&lt;br /&gt;1 Spring MVC 프로젝트 구조&lt;br /&gt;2 MyBatis를 활용한 게시판 구현&lt;br /&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;3 View(JSP) 작성&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;4 Spring 설정 파일&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;5 프로젝트 실행 흐름&lt;br /&gt;&lt;/span&gt;6 오류 해결 과정&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&lt;b&gt;1 Spring MVC 프로젝트 구조&lt;/b&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;1) Spring MVC 패턴 이해&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Spring MVC는 프로젝트를 역할별로 분리하여 개발하는 구조이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사용자의 요청을 Controller가 받고, 실제 업무는 Biz(Service)에서 처리하며, 데이터베이스 작업은 DAO가 담당한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터는 DTO를 이용하여 전달하고, 화면은 JSP가 담당한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉 하나의 요청이 아래와 같은 순서로 진행된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사용자 &amp;rarr; Controller &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;Biz(Service) &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;DAO &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;MyBatis &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;Oracle Database &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;DAO &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;Biz &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;Controller &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;JSP&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MVC 구조를 사용하는 이유는 각각의 역할을 분리하여 유지보수와 확장이 쉬워지기 때문이다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;2) 프로젝트 전체 구조&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트에서 사용한 주요 패키지는 다음과 같다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;com.mvc.upgrade&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HomeController&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;com.mvc.upgrade.model.biz&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BoardBiz&lt;/li&gt;
&lt;li&gt;BoardBizImpl&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;com.mvc.upgrade.model.dao&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BoardDao&lt;/li&gt;
&lt;li&gt;BoardDaoImpl&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;com.mvc.upgrade.model.dto&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BoardDto&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;resources&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;board-mapper.xml&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;WEB-INF/views&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mvclist.jsp&lt;/li&gt;
&lt;li&gt;mvcdetail.jsp&lt;/li&gt;
&lt;li&gt;mvcinsert.jsp&lt;/li&gt;
&lt;li&gt;mvcupdate.jsp&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&lt;b&gt;2 MyBatis를 활용한 게시판 구현&lt;/b&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;1) DTO&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DTO(Data Transfer Object)는 데이터만 저장하는 객체이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;게시글 번호, 작성자, 제목, 내용, 작성일을 하나의 객체로 관리한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;BoardDto에는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;myno&lt;/li&gt;
&lt;li&gt;myname&lt;/li&gt;
&lt;li&gt;mytitle&lt;/li&gt;
&lt;li&gt;mycontent&lt;/li&gt;
&lt;li&gt;mydate&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;필드가 존재하며 getter/setter를 이용하여 값을 저장하고 가져온다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;2) DAO&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DAO(Data Access Object)는 데이터베이스와 직접 통신하는 객체이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 프로젝트에서는 SqlSessionTemplate을 이용하여 MyBatis의 SQL을 실행하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;대표적인 메서드는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;selectList()&lt;/li&gt;
&lt;li&gt;selectOne()&lt;/li&gt;
&lt;li&gt;insert()&lt;/li&gt;
&lt;li&gt;update()&lt;/li&gt;
&lt;li&gt;delete()&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DAO는 SQL을 직접 작성하지 않고 Mapper의 SQL을 호출하는 역할만 담당한다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;3) Biz(Service)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Biz 계층은 Controller와 DAO 사이에서 동작한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Controller가 DAO를 직접 호출하지 않고 Biz를 거쳐서 데이터를 처리하도록 만든다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 구조를 사용하는 이유는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;업무 로직 분리&lt;/li&gt;
&lt;li&gt;유지보수 향상&lt;/li&gt;
&lt;li&gt;기능 추가 시 수정 범위 최소화&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;때문이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;현재 프로젝트에서는 DAO 메서드를 그대로 호출하는 형태로 구현하였다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;4) Controller&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Controller는 사용자의 요청을 가장 먼저 받는 객체이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;list.do&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;요청이 들어오면&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;BoardBiz의 selectList()&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;메서드를 호출하여 게시글 목록을 가져온다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가져온 데이터를 Model에 저장한 후&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;mvclist.jsp&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;화면으로 전달한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사용자 요청 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;Controller &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;Biz &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;DAO &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;Database &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;JSP&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;순서로 실행된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;5) Mapper(XML)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MyBatis에서는 SQL을 XML 파일에 작성한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;board-mapper.xml 안에는&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;select&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;insert&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;update&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;delete&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SQL이 모두 작성되어 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DAO에서는&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;myboard.selectList&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;처럼 namespace와 id만 호출하면 된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SQL과 Java 코드가 분리되어 유지보수가 쉬워진다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&lt;b&gt;3 View(JSP) 작성&lt;/b&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;1) 목록 화면&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;mvclist.jsp&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;게시글 목록을 출력하는 화면이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;JSTL의&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;forEach&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;를 이용하여 게시글을 반복 출력하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상세보기&lt;/li&gt;
&lt;li&gt;글쓰기&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;버튼을 추가하여 페이지 이동이 가능하도록 구현하였다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;2) 상세보기 화면&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;mvcdetail.jsp&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;선택한 게시글 하나를 출력한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;작성자&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;제목&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;내용&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;을 보여주며&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;수정&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;삭제&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;목록&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;버튼을 통해 다음 작업을 수행할 수 있도록 구성하였다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;3) 글 작성 화면&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;mvcinsert.jsp&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;새로운 게시글을 입력하는 화면이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사용자가 입력한 데이터를 Controller로 전송하여&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;insert()&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;메서드를 실행한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;저장이 완료되면&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;list.do&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;로 이동하여 전체 게시글을 다시 조회한다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;4) 글 수정 화면&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;mvcupdate.jsp&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기존 게시글의 정보를 화면에 출력한 후 수정할 수 있도록 구현하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;게시글 번호는 hidden으로 전달하고&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;작성자&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;제목&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;내용&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;만 수정 가능하도록 구성하였다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&lt;b&gt;4 Spring 설정 파일&lt;/b&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;1) applicationContext.xml&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Spring에서 공통으로 사용하는 Bean을 등록하는 파일이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기서는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DataSource&lt;/li&gt;
&lt;li&gt;SqlSessionFactory&lt;/li&gt;
&lt;li&gt;SqlSessionTemplate&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;을 등록하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MyBatis와 Oracle을 연결하는 가장 중요한 설정 파일이다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;2) servlet-context.xml&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Spring MVC 관련 설정을 담당한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;대표적으로&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Controller 검색&lt;/li&gt;
&lt;li&gt;ViewResolver&lt;/li&gt;
&lt;li&gt;Component Scan&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;등을 설정하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Controller를 자동으로 찾아 Bean으로 등록하도록 설정하였다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;3) web.xml&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;웹 프로젝트의 시작점이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기서는&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DispatcherServlet&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;CharacterEncodingFilter&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;를 등록하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;CharacterEncodingFilter를 이용하여 UTF-8 인코딩이 적용되도록 설정하였다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;4) MyBatis config.xml&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MyBatis의 전체 설정 파일이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기서&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;typeAlias&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;mapper&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;를 등록하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Mapper XML을 MyBatis가 읽을 수 있도록 연결하는 역할을 수행한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&lt;b&gt;5 프로젝트 실행 흐름&lt;/b&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;브라우저에서 list.do 요청 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;HomeController &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;BoardBiz &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;BoardDao &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;SqlSessionTemplate &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;board-mapper.xml &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;Oracle Database &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;조회 결과 반환 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;Model 저장 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;mvclist.jsp &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;/span&gt;게시글 목록 출력&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Spring MVC에서는 사용자의 요청이 이러한 흐름으로 처리된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&lt;b&gt;6 오류 해결 과정&lt;/b&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트를 완성하면서 여러 가지 오류를 해결하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;① HTTP 404 오류&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트가 Tomcat에 정상적으로 배포되지 않아 발생하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트를 Maven Project로 설정하고 Server에 다시 등록하여 해결하였다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;② CharacterEncodingFilter 오류&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;encoding 값에&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;true&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가 들어가 있어&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;UTF-8&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;로 수정하였다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;③ SqlSessionTemplate Bean 오류&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;No qualifying bean of type SqlSessionTemplate&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;오류가 발생하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;원인은 applicationContext.xml에서 Bean 이름과 참조 이름이 일치하지 않았기 때문이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SqlSessionFactory와 SqlSessionTemplate 설정을 수정하여 해결하였다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;④ Spring 버전 충돌&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Spring 5 프로젝트에서&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;spring-orm 7.x&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;를 사용하고 있어 Bean 생성 오류가 발생하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Spring Framework 버전을 모두 5.3.x로 통일하여 해결하였다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&lt;b&gt;오늘 배운 내용&lt;/b&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 프로젝트에서는 Spring MVC와 MyBatis를 이용하여 게시판 CRUD 프로젝트를 완성하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MVC 구조에서 Controller, Biz, DAO, DTO의 역할을 이해하였고, MyBatis Mapper를 이용하여 SQL을 분리하는 방법을 학습하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한 JSP 화면 작성부터 Spring 설정 파일, Oracle 연동, 오류 해결까지 하나의 프로젝트를 완성하는 전체 흐름을 경험할 수 있었다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 프로젝트를 통해 Spring MVC 프로젝트가 실제로 어떻게 동작하는지 전체 구조를 이해할 수 있었으며, 앞으로 REST API나 Spring Boot를 학습하기 위한 기초를 다질 수 있었다.&lt;/p&gt;</description>
      <category>멀티캠퍼스</category>
      <category>[현대이지웰] Java 풀스택 개발자 아카데미 8회차</category>
      <category>멀티캠퍼스부트캠프</category>
      <category>부트캠프</category>
      <author>buckwheat</author>
      <guid isPermaLink="true">https://buckwheat0.tistory.com/70</guid>
      <comments>https://buckwheat0.tistory.com/70#entry70comment</comments>
      <pubDate>Thu, 25 Jun 2026 02:52:34 +0900</pubDate>
    </item>
  </channel>
</rss>