<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Re-start</title>
        <link>https://velog.io/</link>
        <description>restart</description>
        <lastBuildDate>Tue, 23 May 2023 05:35:56 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Re-start</title>
            <url>https://velog.velcdn.com/images/hajin-dev/profile/dc6fff84-e5e7-4bbe-8e0f-fef01345204f/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Re-start. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hajin-dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[PostgreSQL] 원격 DB서버 설정]]></title>
            <link>https://velog.io/@hajin-dev/PostgreSQL-%EC%9B%90%EA%B2%A9-DB%EC%84%9C%EB%B2%84-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@hajin-dev/PostgreSQL-%EC%9B%90%EA%B2%A9-DB%EC%84%9C%EB%B2%84-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Tue, 23 May 2023 05:35:56 GMT</pubDate>
            <description><![CDATA[<p>기준 Ubuntu20.04, PostgreSQL 15</p>
<ol>
<li><code>/etc/postgresql/[버전]/main</code>로 이동</li>
<li>postgresql.conf를 root권한으로 편집하여 <code>listen_port=&quot;localhost&quot;</code>의 주석을 해제하여 <code>listen_port=&quot;*&quot;</code>로 바꾼다.</li>
<li><code>pg_hba.conf</code>도 마찬가지로 root 권한으로 편집하여 <pre><code># IPv4 local connections:
host    all             all             127.0.0.1/32            </code></pre>를<pre><code># IPv4 local connections:
host    all             all             0.0.0.0/0            </code></pre>로 바꾼다.</li>
<li><code>PostgreSQL</code>서비스 재시작</li>
<li>알맞게 방화벽 설정이나 포트포워딩을 진행</li>
<li>원격 접속 테스트</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PostgreSQL] 클라이언트 리눅스 명령어 모음]]></title>
            <link>https://velog.io/@hajin-dev/PostgreSQL-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EB%A6%AC%EB%88%85%EC%8A%A4-%EB%AA%85%EB%A0%B9%EC%96%B4-%EB%AA%A8%EC%9D%8C</link>
            <guid>https://velog.io/@hajin-dev/PostgreSQL-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EB%A6%AC%EB%88%85%EC%8A%A4-%EB%AA%85%EB%A0%B9%EC%96%B4-%EB%AA%A8%EC%9D%8C</guid>
            <pubDate>Fri, 19 May 2023 03:05:32 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hajin-dev/post/03a1c68a-00cb-432a-a2dd-23130525ed11/image.png" alt=""></p>
<p>기준: PostgreSQL 15.3 및 Ubuntu 22.04</p>
<table>
<thead>
<tr>
<th align="left">커맨드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><code>pg_archivecleanup</code></td>
<td>PostgreSQL WAL 아카이브 파일들을 정리함 <a href="https://www.postgresql.org/docs/15/pgarchivecleanup.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_backupcluster</code></td>
<td>pg_basebackup랑 pg_dump front-end 동시 실행 하는 간단 커맨드 <a href="https://manpages.ubuntu.com/manpages/jammy/man1/pg_backupcluster.1.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_basebackup</code></td>
<td>PostgreSQL의 클러스터를 베이스 백업 <a href="https://www.postgresql.org/docs/15/app-pgbasebackup.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_buildext</code></td>
<td>PostgreSQL의 확장을 설치, 빌드 <a href="https://manpages.ubuntu.com/manpages/jammy/man1/pg_buildext.1.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_config</code></td>
<td>PostgreSQL의 여러 설정을 보여줌 <a href="https://www.postgresql.org/docs/current/app-pgconfig.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_conftool</code></td>
<td>PostgreSQL 클러스터의 설정 파일들을 읽고 편집함 <a href="https://manpages.ubuntu.com/manpages/jammy/man1/pg_conftool.1.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_createcluster</code></td>
<td>PostgreSQL 클러스터를 새로 만듦 <a href="https://manpages.ubuntu.com/manpages/jammy/en/man1/pg_createcluster.1.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_ctlcluster</code></td>
<td>PostgreSQL 클러스터를 시작, 멈추기, 재시작, 리로드 <a href="https://manpages.ubuntu.com/manpages/jammy/en/man1/pg_ctlcluster.1.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_dropcluster</code></td>
<td>PostgreSQL 클러스터를 완전하게 <em>지움</em> <a href="https://manpages.ubuntu.com/manpages/jammy/en/man1/pg_dropcluster.1.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_dump</code></td>
<td>PostgreSQL DB를 스크립트 파일이나 아카이브 파일로 변환해서 가져옴 <a href="https://www.postgresql.org/docs/current/app-pgdump.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_dumpall</code></td>
<td>PostgreSQL DB <em>클러스터</em>를 스크립트 파일이나 아카이브 파일로 변환해서 가져옴 <a href="https://www.postgresql.org/docs/15/app-pg-dumpall.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_isready</code></td>
<td>PostgreSQL 클러스터 서버와 연결되었는지 확인 <a href="https://www.postgresql.org/docs/15/app-pg-isready.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_lsclusters</code></td>
<td>PostgreSQL 클러스터의 리스트를 출력 <a href="https://manpages.ubuntu.com/manpages/jammy/en/man1/pg_lsclusters.1.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_receivewal</code></td>
<td>PostgreSQL 서버로부터의 로그를 중계함 <a href="https://www.postgresql.org/docs/15/app-pgreceivewal.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_receivexlog</code></td>
<td><code>pg_receivewal</code>랑 같은 커맨드 <a href="https://www.postgresql.org/docs/15/app-pgreceivexlog.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_recvlogical</code></td>
<td>논리 디코딩 스트림 제어 <a href="https://www.postgresql.org/docs/15/app-pgrecvlogical.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_renamecluster</code></td>
<td>PostgreSQL 클러스터의 이름을 재정의 <a href="https://manpages.ubuntu.com/manpages/jammy/man1/pg_renamecluster.1.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_restore</code></td>
<td><code>pg_dump</code>로 생성된 백업(아카이브) 파일로부터 복구 <a href="https://www.postgresql.org/docs/15/app-pgrestore.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_restorecluster</code></td>
<td><code>pg_backupcluster</code>로 생성된 백업(아카이브) 파일로부터 복구 <a href="https://manpages.ubuntu.com/manpages/jammy/en/man1/pg_restorecluster.1.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_upgradecluster</code></td>
<td>PostgreSQL 클러스터를 새 메이져 버전으로 업그레이드 <a href="https://manpages.ubuntu.com/manpages/jammy/en/man1/pg_upgradecluster.1.html">#</a></td>
</tr>
<tr>
<td align="left"><code>pg_virtualenv</code></td>
<td>커맨드를 종료할 때까지 지속되는 PostgreSQL 서버 가상 환경을 만듦, 실행되는 동안 환경변수가 설정되어 접근할 수 있음  <a href="https://manpages.ubuntu.com/manpages/jammy/man1/pg_virtualenv.1.html">#</a></td>
</tr>
</tbody></table>
<p>... 공부 더 해야겠다 </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SpringBoot에서 MySQL로 데이터 접근]]></title>
            <link>https://velog.io/@hajin-dev/SpringBoot%EC%97%90%EC%84%9C-MySQL%EB%A1%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%91%EA%B7%BC</link>
            <guid>https://velog.io/@hajin-dev/SpringBoot%EC%97%90%EC%84%9C-MySQL%EB%A1%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%91%EA%B7%BC</guid>
            <pubDate>Tue, 18 Apr 2023 08:30:02 GMT</pubDate>
            <description><![CDATA[<p><a href="https://spring.io/guides/gs/accessing-data-mysql/">원문</a></p>
<p>This guide walks you through the process of creating a Spring application connected to a MySQL Database (as opposed to an in-memory, embedded database, which most of the other guides and many sample applications use). It uses Spring Data JPA to access the database, but this is only one of many possible choices (for example, you could use plain Spring JDBC).
이 가이드는 스프링 애플레이케이션을 MySQL 데이터베이스에 접속하는 흐름에 대한 가이드입니다. DB에 접근을 위해서 스프링 데이터 JPA를 활용하지만 반드시 이걸 쓸 필요는 없고 Spring JDBC만 써서 DB를 관리하는 것도 방법일 수 있습니다.</p>
<h3 id="필요한-것">필요한 것</h3>
<ul>
<li>MYSQL 5.6버전 이상<ul>
<li>도커를 설치했다면 데이터베이스를 컨테이너에서 기동하는 것도 좋은 선택지 일 수 있습니다.</li>
</ul>
</li>
<li>소요시간 15분</li>
<li>IDE 혹은 에디터</li>
<li>JAVA 17 이상</li>
<li>Gradle 7.5이상 혹은 Maven 3.5 이상</li>
</ul>
<h3 id="spring-생성기로-프로젝트-시작">Spring 생성기로 프로젝트 시작</h3>
<blockquote>
<p><a href="https://start.spring.io/#!type=maven-project&amp;language=java&amp;platformVersion=3.0.1&amp;packaging=jar&amp;jvmVersion=17&amp;groupId=com.example&amp;artifactId=accessing-data-mysql&amp;name=accessing-data-mysql&amp;description=Demo%20project%20for%20Spring%20Boot&amp;packageName=com.example.accessing-data-mysql&amp;dependencies=web,data-jpa,mysql">이 링크</a>를 통해 미리 패키지명과 필요한 라이브러리가 들어간 Spring 프로젝트를 가져올 수 있습니다.</p>
</blockquote>
<p><a href="https://start.spring.io/%EC%97%90">https://start.spring.io/에</a> 접속해서 원하는 환경을 설정한 이후에 <strong>Spring Web</strong>, <strong>Spring Data JPA</strong> 과 <strong>MySQL Driver</strong>를 가겨오고 압축된 프로젝트를 원하는 경로에 풀어서 편집기나 IDE로 엽니다.
<em>VSCODE나 IntelliJ처럼 자체 Spring Initializer가 있으면 그걸로 생성해도 좋아요!!</em></p>
<h3 id="db-만들기">DB 만들기</h3>
<p>IDE나 콘솔로 프로젝트 경로에 터미널을 열고, MySQL client를 실행해 새 유저를 만듭니다. 리눅스에서는  <code>sudo mysql --password</code>를  윈도우면 MySQL WorkBench등을 이용해서 진행합니다.</p>
<blockquote>
<p>이때 주의할 점은 root 계정으로 진행하면 모든 host의 DB에 접근할 수 있으니, 반드시 실습용 환경에서 진행하도록 합니다.</p>
</blockquote>
<p>새 DB를 만들기 위해 mySQL 프롬프트에 커맨드를 아래와 같이 입력합니다.</p>
<pre><code>mysql&gt; create database db_example; -- Creates the new database
mysql&gt; create user &#39;springuser&#39;@&#39;%&#39; identified by &#39;ThePassword&#39;; -- Creates the user
mysql&gt; grant all on db_example.* to &#39;springuser&#39;@&#39;%&#39;; -- Gives all privileges to the new user on the newly created database</code></pre><h3 id="applicationproperties-파일-생성">application.properties 파일 생성</h3>
<p>스프링 부트는 모든 설정에 기본 설정이 있습니다. 예를 들어 기본 데이터베이스는 <code>H2</code>인데, 다른 데이터베이스를 써야한다면, <code>application.properties</code>파일에서 연결 속성을 할당해야합니다. <code>src/main/resources/application.properties</code>처럼 써진대로 경로와 파일을 만들어서 아래와 같이 써줍시다.</p>
<pre><code>spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=ThePassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.jpa.show-sql: true</code></pre><p>여기서 <code>spring.jpa.hibernate.ddl-auto</code>는 아래와 같은 속성을 할당 할 수 있습니다.
|속성|설명|
|:-|:-|
|<code>none</code>|MySQL에서 기본으로 설정됩니다. 데이터베이스 구조에 변화가 없습니다.|
|<code>update</code>|하이버네이트가 객체 구조에 따라  데이터베이스를 바꿉니다.|
|<code>create</code>|데이터베이스를 항상 생성하되, 닫더라도 DROP(DB 삭제)하지 않습니다.|
|<code>create-drop</code>|데이터베이스를 생성한 후 <code>SessionFactory</code>가 닫히면 지워집니다.|</p>
<p>일단 데이터베이스 구조를 가지고 있지 않으니까 <code>create</code>나 <code>update</code>로 시작합시다. 프로젝트를 한번 실행하면 프로그램 요구사항에 따라 <code>update</code>나 <code>none</code>으로 바꿀 수 있습니다. <code>update</code>는 데이터베이스 구조를 바꿔야할 때 씁시다.</p>
<p>기본 설정인 H2를 포함에 다른 임베디드 데이터베이스의 기본은 <code>create-drop</code>이고, MySQL을 비롯한 몇몇 데이터베이스들의 기본은 <code>none</code>입니다.</p>
<blockquote>
<p>데이터베이스가 프로덕션 상태가 된 후 이를 none으로 설정하고 Spring 애플리케이션에 연결된 MySQL 사용자의 모든 권한을 취소하고 MySQL 사용자에게 SELECT, UPDATE, INSERT 및 DELETE만 부여하는 것이 좋은 보안 방법입니다.  자세한 건 이 가이드 마지막에 볼 수 있습니다.</p>
</blockquote>
<h3 id="entity-모델-생성">@Entity 모델 생성</h3>
<p><code>src/main/java/com/example/accessingdatamysql/User.java</code>에 지정된 경로 아래 파일을 생성해서 아래와 같이 써서 객체 모델을 생성합시다.</p>
<pre><code>package com.example.accessingdatamysql;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity // This tells Hibernate to make a table out of this class
public class User {
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Integer id;

  private String name;

  private String email;

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getEmail() {
    return email;
  }

  public void setEmail(String email) {/5
    this.email = email;
  }
}</code></pre><p>Hibernate가 알아서 자동으로 객체를 테이블 형태로 변환합니다.</p>
<h3 id="저장소repository-생성">저장소(Repository) 생성</h3>
<p>유저 기록을 저장할 저장소를 생성하기 위해 <code>src/main/java/com/example/accessingdatamysql/UserRepository.java</code>에 파일을 생성해 아래와 같이 작성합시다.</p>
<pre><code>package com.example.accessingdatamysql;

import org.springframework.data.repository.CrudRepository;

import com.example.accessingdatamysql.User;

// This will be AUTO IMPLEMENTED by Spring into a Bean called userRepository
// CRUD refers Create, Read, Update, Delete

public interface UserRepository extends CrudRepository&lt;User, Integer&gt; {

}</code></pre><p>스프링은 자동적으로 동명의 빈 bean내의 저장소 인터페이스를 자동으로 구현합니다. 위에서 <code>useRepository</code>로 생성됩니다.</p>
<h3 id="컨트롤러-생성">컨트롤러 생성</h3>
<p>애플리케이션의 HTTP 요청을 다루기 위해 컨트롤러를 생성해야합니다.
src/main/java/com/example/accessingdatamysql/MainController.java로 파일을 생성합시다.</p>
<pre><code>package com.example.accessingdatamysql;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller // This means that this class is a Controller
@RequestMapping(path=&quot;/demo&quot;) // This means URL&#39;s start with /demo (after Application path)
public class MainController {
  @Autowired // This means to get the bean called userRepository
         // Which is auto-generated by Spring, we will use it to handle the data
  private UserRepository userRepository;

  @PostMapping(path=&quot;/add&quot;) // Map ONLY POST Requests
  public @ResponseBody String addNewUser (@RequestParam String name
      , @RequestParam String email) {
    // @ResponseBody means the returned String is the response, not a view name
    // @RequestParam means it is a parameter from the GET or POST request

    User n = new User();
    n.setName(name);
    n.setEmail(email);
    userRepository.save(n);
    return &quot;Saved&quot;;
  }

  @GetMapping(path=&quot;/all&quot;)
  public @ResponseBody Iterable&lt;User&gt; getAllUsers() {
    // This returns a JSON or XML with the users
    return userRepository.findAll();
  }
}</code></pre><blockquote>
<p>위에서는 두 도달점에 대해 POST 및 GET을 명시적으로 지정합니다. 기본적으로 @RequestMapping은 모든 HTTP 작업을 매핑합니다.</p>
</blockquote>
<h3 id="어플리케이션-클래스-생성">어플리케이션 클래스 생성</h3>
<p>Spring Initializer  (저 위에 링크들...)에서 간단하게 클래스를 만듭니다. 아래에 있는건 Spring Initializer에서 자동으로 만든 클래스입니다.</p>
<pre><code>package com.example.accessingdatamysql;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AccessingDataMysqlApplication {

  public static void main(String[] args) {
    SpringApplication.run(AccessingDataMysqlApplication.class, args);
  }

}</code></pre><p>예를 들어 위의 <code>AccessingDataMysqlApplication</code>클래스를 조정할 경우,
<code>@SpringBootApplication</code>은 아래의 것을 3가지  포괄하는 편한 어노테이션</p>
<p><code>@Configuration</code>: 해당 클래스가 스프링 자체의 설정파일임을 알리는 어노테이션
<code>@EnableAutoConfiguration</code>:스프링 부트의 class 시작 경로를 알려주고, bean을 추가해주는 어노테이션 
<code>@ComonentScan</code> 스프링에게 다른 컴포넌트와 설정, 서비스를 패키지(여기선 com/example)에게 알려주고 컨트롤러가 인지하게 함</p>
<p>main() 메소드는 스프링 부트의 <code>SpringApplication.run()</code>을 사용해 어플리케이션을 실행합니다. XML하나 없이 웹 애플리케이션이 만들어집니다.</p>
<h3 id="이제-실행-가능한-jar-생성">이제 실행 가능한 JAR 생성</h3>
<p>이제 Maven이나 Gradle로 어플리케이션을 가농할 수 있습니다.</p>
<p><code>./gradlew bootRun</code>으로 실행 혹은 <code>./gradlew build</code>후 <code>java -jar build/libs/gs-accessing-data-mysql-0.1.0.jar</code>으로 빌드를 자바로 직접 실행해도 됩니다.</p>
<p>만약 Maven을 쓴다면 <code>./mvnw spring-boot:run</code>으로 기동하거나 <code>./mvnw</code>만 친 이후 <code>java -jar target/gs-accessing-data-mysql-0.1.0.jar</code>로 빌드를 직접 실행해도 됩니다. 실행하면 자바 콘솔에 로그들이 나옵니다.</p>
<h3 id="어플리케이션-테스트">어플리케이션 테스트</h3>
<p>자 이제 curl이나 비슷한 도구들을 이용해 HTTP 응답으로 테스트 해봅시다.</p>
<p><code>GET localhost:8080/demo/all</code> 모든 데이터 수신
<code>POST localhost:8080/demo/add</code> 단일 유저 데이터 추가</p>
<p>아래와 같이 콘솔에 입력시</p>
<p><code>$ curl http://localhost:8080/demo/add -d name=First -d email=someemail@someemailprovider.com</code></p>
<p>이런 응답이 올 것이고</p>
<p><code>Saved</code></p>
<p>비슷하게 이렇게 입력시
<code>$ curl http://localhost:8080/demo/all</code></p>
<p>이런 응답이 올겁니다.
<code>[{&quot;id&quot;:1,&quot;name&quot;:&quot;First&quot;,&quot;email&quot;:&quot;someemail@someemailprovider.com&quot;}]</code></p>
<h3 id="보안-조정">보안 조정</h3>
<p>이걸 Production 으로 들어갈 경우 SQL 삽입 공격에 취약할 수 있습니다. 해커는 DROP TABLE와 같은 파괴적인 SQL명령을 삽입할 수 있기에 보안적 실습 차원에서 데이터베이스에 조정이 필요합니다.</p>
<p>아래와 같은 커맨드는 스프링 애플리케이션과 연결된 사용자 모든 권한을 취소합니다.
<code>mysql&gt; revoke all on db_example.* from &#39;springuser&#39;@&#39;%&#39;;</code></p>
<p>이제 스프링 어플리케이션은 데이터베이스에 아무것도 못합니다.
그래도 어플리케이션에 권한은 있어야 하니 최소한의 권한은 줍시다.</p>
<p><code>mysql&gt; grant select, insert, delete, update on db_example.* to &#39;springuser&#39;@&#39;%&#39;;</code>
모든 권한 제거 후 일부 권한을 주는 것으로 스프링 애플리케이션이 데이터베이스의 데이터만 변경하는 권한을 가집니다. 
데이터 베이스를 바꾸는 경우 </p>
<ol>
<li>권한 재부여</li>
<li><code>spring.jpa.hibernate.ddl-auto</code>을 <code>update</code>로 변경</li>
<li>어플리케이션 재실행</li>
</ol>
<p>후에 앞의 것을 반복해 다시 어플리케이션을 보호할 수 있습니다. <code>Flyway</code>나 <code>Luqyubase</code>를 이용해 마이그레이션 도구를 이용하는 것도 좋은 방법입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SPRING-BOOT와 GRADLE로 RESTful 웹 서비스 시작]]></title>
            <link>https://velog.io/@hajin-dev/SPRING-BOOT%EC%99%80-GRADLE%EB%A1%9C-RESTful-%EC%9B%B9-%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%8B%9C%EC%9E%91</link>
            <guid>https://velog.io/@hajin-dev/SPRING-BOOT%EC%99%80-GRADLE%EB%A1%9C-RESTful-%EC%9B%B9-%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%8B%9C%EC%9E%91</guid>
            <pubDate>Mon, 10 Apr 2023 04:26:42 GMT</pubDate>
            <description><![CDATA[<p><a href="https://spring.io/guides/gs/rest-service/#initial">공식 튜토리얼</a>
이 가이드는 &quot;Hello,World&quot; 출력하는 RESTful 웹 서비스를 만드는 과정에 대한 가이드 입니다.</p>
<h4 id="당신이-만들-것">당신이 만들 것</h4>
<p>이 튜토리얼을 통해 <a href="http://localhost:8080/greeting">http://localhost:8080/greeting</a> 에 접속할 시에 JSON형태로</p>
<pre><code>{&quot;id&quot;:1,&quot;content&quot;:&quot;Hello, World!&quot;}</code></pre><p>의 형태의 리스트가 출력 됩니다.</p>
<p>또, url에 name 패러미터를 통해 쿼리 문자열을 입력해 
<a href="http://localhost:8080/greeting?name=User">http://localhost:8080/greeting?name=User</a> 로 접속시 </p>
<pre><code>{&quot;id&quot;:1,&quot;content&quot;:&quot;Hello, User!&quot;}</code></pre><p>로 문자열이 출력 될 것입니다.</p>
<h4 id="필요한-것">필요한 것</h4>
<ul>
<li>15분 정도의 시간</li>
<li>자신에게 맞는 IDE혹은 텍스트 편집기</li>
<li>JAVA17+</li>
<li>Gradle 7.5+ 혹은 Maven 3.5+</li>
<li>해당 IDE를 사용시 프로젝트를 바로 만들 수 있습니다.<ul>
<li>Spring Tool Suite (STS)</li>
<li>Intellij IDEA</li>
<li>VSCode</li>
</ul>
</li>
</ul>
<p><a href="https://github.com/spring-guides/gs-rest-service.git%ED%95%B4%EB%8B%B9">https://github.com/spring-guides/gs-rest-service.git해당</a> 링크를 통해 프로젝트 생성 과정 스킵 가능</p>
<p>IDE나 위의 깃을 쓰지 않을 경우...</p>
<ol>
<li><a href="https://start.spring.io/#!type=maven-project&amp;groupId=com.example&amp;artifactId=rest-service&amp;name=rest-service&amp;description=Demo%20project%20for%20Spring%20Boot&amp;packageName=com.example.rest-service&amp;dependencies=web">https://start.spring.io/</a>에 접속하여 프로젝트 명과 자신에게 맞는 환경으로 설정합시다.</li>
<li>dependencies에서 <code>Spring Web</code>을 선택합시다.</li>
<li>생성하고 zip으로 다운로드 하여 프로젝트 편집 시작!</li>
</ol>
<h4 id="이제-리소스-재출력-클래스를-만들어-보기">이제 리소스 재출력 클래스를 만들어 보기</h4>
<p>이제 <code>gradle tasks</code>를 통해 빌드를 합니다. 이제 웹 서비스를 만들 수 있습니다.
우리 한번 서비스가 어떻게 동작할 것인지를 생각해봅시다.
서비스는 <code>/greeting</code>으로의 requests의 GET를 다룰겁니다. 그리고 임의로 <code>name</code> 패러미터로 쿼리 문자열을 받습니다. 그리고 GET 요청에 대하 응답으로 <code>200 ok</code> 응답을 json을 담은 문서와 함께 출력해아합니다. </p>
<pre><code>{
    &quot;id&quot;: 1,
    &quot;content&quot;: &quot;Hello, World!&quot;
}</code></pre><p><code>id</code> 항목은 고유 식별자이며, <code>content</code>는 Greeting에 대한 텍스트 주요 표현법입니다. 
이를 model화 하기 위해 resource representation class를 만들어 봅시다. 먼저 Java record class를 만들고 <code>id</code>와 <code>content</code> 데이터를 줍시다. <code>src/main/java/{패키지 이름}/Greeting.java</code>을 생성한 이후 해당 파일에</p>
<pre><code>package com.example.restservice;

public record Greeting(long id, String content) { }</code></pre><p>를 작성합니다.</p>
<h4 id="리소스-컨트롤러resource-controller-생성">리소스 컨트롤러(Resource Controller) 생성</h4>
<p>RESTful 웹 서비스를 만들기 위한 Spring식 접근아래 HTTP 요청은 컨트롤러에 의해 관리됩니다. 이 컴포넌트들은 <code>@ResController</code> 어노테이션(annotaion)에 의해 구조가 정의되고, 목록(<code>src/main/java/{패키지 이름}/GreetingController.java</code>)에 표시된 GreetingController는 Greeting의 새 인스턴스를 반환하여 <code>/greeting</code>에 대한 GET 요청을 처리합니다.</p>
<pre><code>package com.example.restservice;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

    private static final String template = &quot;Hello, %s!&quot;;
    private final AtomicLong counter = new AtomicLong();

    @GetMapping(&quot;/greeting&quot;)
    public Greeting greeting(@RequestParam(value = &quot;name&quot;, defaultValue = &quot;World&quot;) String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
}</code></pre><p>이 컨트롤러는 단순간결 합니다. 그러나 실제로는 많은 작업들이 진행되고 있습니다. 하나씩 파헤쳐 봅시다.</p>
<pre><code>...
@GetMapping(&quot;/greeting&quot;)
    public Greeting greeting(@RequestParam(value = &quot;name&quot;, defaultValue = &quot;World&quot;) String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
...</code></pre><p><code>@GetMapping</code>어노테이션은 <code>/greeting</code>으로 연결된 HTTP GET요청이 <code>greeting()</code> 메소드에 연결 되었는지 확인합니다. </p>
<blockquote>
<p>GET이 아닌 POST등의 Request의 경우는 @POSTMapping이나 @RequestMapping(method=POST)등으로 사용</p>
</blockquote>
<pre><code>...
public Greeting greeting(@RequestParam(value = &quot;name&quot;, defaultValue = &quot;World&quot;) String name) {...}
...</code></pre><p><code>@RequestParamd</code>은 패러미터를 통해 받아온 <code>name</code>의값을 <code>greeting</code> 메소드의 <code>name</code>패러미터에 전달합니다. <code>name</code>패러미터가 없으면 이미 설정된 기본 값인 <code>World</code>로 전달 됩니다.</p>
<p>메소드 본문의 구현은 Greeing 템플릿을 사용해서 counter로 갱신된 다음 숫자 값과 , 받아온 문자열을 알맞게 포맷팅하여 나온 문자 값을 바탕으로 id와 content속성이 부여된 Greeting 객체를 리턴합니다.</p>
<p>기존 MVC컨트롤러와 예제와 같은 MVC컨트롤러간의 차이점은 HTTP응답 본 내용이 생성되는 방식입니다. 예제의 RESTful 웹 서비스 컨트롤러는 기존의 Greeting 응답 본문을 출력하기 위해 서버측에서 html렌더링을 수행하며 view기술에 의존하기 보단 <code>Greeting</code> 객체를 생성하고 리턴합니다. 이 객체 데이터는 JSON형태의 HTTP 응답으로 즉시 쓰여집니다.</p>
<p>이 예제는 모든 메소드를 뷰 대신 도메인 객체로 반환하는 컨트롤러이자 클래스인  <code>@RestController</code> 어노테이션을 사용합니다.</p>
<p>Greeting 객체는 반드시 JSON으로 변환되어야 합니다.
다행히 Jackson 2가 클래스path에 있어서 Spring의 <code>MappingJackson2HttpMessageConverter</code>가 자동적으로 <code>Greeting</code> 인스턴스를 Json으로 변환합니다. 그래서
Spring에서 http 메시지를 변화기를 지원해서 수동으로 코드를 더 짤 필요가 없습니다!
<code>@SpringBootApplication</code>은 아래의 내용을 모두 추가하는 편리한 어노테이션입니다.</p>
<ul>
<li><code>@Configuration</code>은 애플리케이션 context를 위한 bean에 대한 출처를 클래스로서 지정함을 수행합니다.</li>
</ul>
<blockquote>
<p>참고: java bean은 무엇인가?<a href="https://docs.oracle.com/javase/6/docs/api/java/beans/package-summary.html">https://docs.oracle.com/javase/6/docs/api/java/beans/package-summary.html</a></p>
</blockquote>
<ul>
<li><p><code>@EnableAutoConfiguration</code>은 Spring Boot에게 클래스 경로나 bean, 프로퍼티 설정을 알려줘 Spring Boot가 bean들을 추가하게 해줍니다. 예를 둘어 만약 <code>spring-webmvc</code>가 <code>classpath</code>에 있을시 어노테이션은 어플리케이션을 웹 어플리케이션으로,  key의 행동을 가리킵니다. (예: <code>DIspatcherServlet</code>)</p>
</li>
<li><p><code>@ComponentScan</code>: 스프링에게 다른 구성요소 어노테이션이나 설정, 서비스들을 <code>com/example</code>에서 찾아 자동으로 등록하게 합니다.</p>
</li>
</ul>
<p><code>main()</code> 메소드는 스프링 부트의 <code>SpringApplication.run()</code> 메소드를 실행해 어플리케이션을 배포합니다. xml 한줄도 없었던거 눈치 채셨나요? web.xml 파일 하나도 없습니다. 이 웹 어플리케이션은 100% java이고 설정이나 구조 짜는데 씨름할 필요가 없는 예제입니다.</p>
<h4 id="jar-빌드-그리고-실행">JAR 빌드 그리고 실행</h4>
<p>이제 애플리케이션을 콘솔에서 Gradle이나 Maven으로 실행할 수 있습니다. 아니면 필요한 의존들이나 클래스나 자원들을 모두 담고 실행가능한 JAR 파일을 빌드할 수도 있습니다. 실행 가능한 JAR 파일을 빌드하면 개발 지원 시기까지, 다양한 환경에서 서비스를 애플리케이션 형태로 쉽게 제공하여 버전을 지정해 배포할 수 있습니다.</p>
<p>Gradle을 실행하면, <code>./gradlew bootRun</code>을 통해 어플리케이션을 실행할 수 있습니다. 아니면<code>./gradlew build</code>를 써서 빌드 후 JAR파일을 <code>java -jar build/libs/{압력한 프로젝트 이름}.jar</code>로 실행해서 쓸 수 있습니다.</p>
<p>Maven을 쓸 경우, <code>./mvnw spring-boot:run</code>으로 어플리케이션을 실행할 수 있습니다. 마찬가지로 JAR파일을 <code>./mvnw clean pacakge</code>로 빌드후 JAR파일을 <code>java -jar target/{압력한 프로젝트 이름}.jar</code>으로 실행하면 됩니다.</p>
<h4 id="서비스-테스트">서비스 테스트</h4>
<p>이제 서비스가 시작되었습니다. 위와 같은 과정으로 실행한 이후, <a href="http://localhost:8080/greeting">http://localhost:8080/greeting</a> 를 들려 봅시다. 들렸다면</p>
<pre><code>{&quot;id&quot;:1,&quot;content&quot;:&quot;Hello, World!&quot;}</code></pre><p>를 볼 수 있습니다. 이제 쿼리 문자열을 추가합시다.
<a href="http://localhost:8080/greeting?name=User%EB%A1%9C">http://localhost:8080/greeting?name=User로</a> 방문시</p>
<pre><code>{&quot;id&quot;:2,&quot;content&quot;:&quot;Hello, User!&quot;}</code></pre><p>가 나옵니다.</p>
<p>다르게 준 값으로 <code>GreetingController</code>의 <code>@RequestParam</code>의 활용이 예상대로 동작하고 있습니다. <code>name</code>패러미터는 <code>World</code>가 기본 값이지만 쿼리 문자열로 인해 값이 덮어 쓰여질 수 있습니다.</p>
<p>또, <code>id</code> 속성이 <code>1</code>에서 <code>2</code>로 변경된 걸 알 수 있습니다. 이것은 <code>GreetingController</code>를 여러번 요청 한 것으로 <code>counter</code> 필드의 값 상승이 부를 때마다 된 것임을 예상할 수 있습니다.</p>
]]></description>
        </item>
    </channel>
</rss>