레쭈고 혼공부뚜! (Spring Boot)

혼공부뚜 1주 차 ( ⸝⸝⸝ᵔᵔ⸝⸝⸝ )

정땅미 2025. 4. 13. 16:42

드디어 제가 다시 하고 싶었다던 혼공족을 시작하게 되었습니다아~~ 박수우 (👏🏻)

지금은 취업 준비, 시험, 졸업 전시회와도 점점 가까워지고 있어 잘 끝낼 수 있을지 두렵지만

제가 할 수 있는 최선을 다 해 또 열심히 해 보려 합니다! ദ്ദി ( ᵔ ᗜ ᵔ )

이번엔 스프링부트를 배우기로 결심했기에, 열심히 해보도록 하겠숩니닷!! 


스프링 부트란?

- 자바 웹 프로그램을 더욱 쉽게 빠르게 만들기 위한 도구!

localhost 란?

- 실행 중인 서버의 주소 중 특별한 주소 : 내 컴퓨터

- IP 주소로 변경하면 127.0.0.1 이 된다~ ˶ᵔ'ヮ'ᵔ˶

8080 이란?

- 포트 번호! : 방 번호 느낌

톰캣이란?

- 웹 서버를 말한다! 스프링 부트는 톰캣에 담겨 실행된다!

뷰란?

- 화면을 담당하는 기술로, 웹 페이지를 하나의 틀로 만들고 여기에 변수를 삽입해 다른 페이지로 보여준다!

- 우리가 프로젝트를 만들 때 추가한 Mustache 라는 도구가 뷰 템플릿을 만들어 준다~ (ᐢᗜᐢ)

컨트롤러란?

- 클라이언트의 요청에 따라 서버에서 이를 처리하는 역할!

모델이란?

- 데이터를 관리하는 역할~

MVC 패턴이란?

웹 페이지를 화면에 보여주고, 클라이언트의 요청을 받아 처리하고, 데이터를 관리하는 역할을 나누는 기법이드아!

어노테이션이란?

- 소스 코드에 추가해 사용하는 메타 데이터의 일종으로 @ 기호를 붙여 사용한다.

package com.example.firstproject.controller;

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

@Controller
public class FirstController {

    @GetMapping("/hi")
    public String niceToMeetYou() {
        return "greetings";
    }
}

 

뷰 템플릿 페이지를 만들고, 컨트롤러를 만들어서 제대로 된 결과값을 띄워줬는데요!

@Controller 를 먼저 선언하고 반환값으로 보여 줄 페이지의 이름만 따서 적고, 마지막으로 @GetMapping 을 이용해서 URL 접수 요청을 해 주었답니다!

그래서 localhost:8080/hi 로 접속하면 제가 greetings.mustache 에 작성했던 코드가 나오게 됩니다!

짜란 ˆ ⩌ ˆ

 

<h1>{{username}}님, 반갑습니다!</h1>
package com.example.firstproject.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class FirstController {

    @GetMapping("/hi")
    public String niceToMeetYou(Model model) {
        model.addAttribute("username", "땅미");
        return "greetings";
    }
}

 

첫 번째 코드는요!

제가 greeting.mustache 파일에서 홍팍이라는 이름을 제 마음대로 바꾸고 싶어서 변수를 설정해 줬어요!

형식이 살짝 신기한데요~ { { 변수명 } } 이렇게 중괄호 두 개로 감싸고 안에 변수명을 써주면 된대요~ ⸜( ◜࿁◝ )⸝︎︎

그래서 저는 username 을 써 줬고 이를 Model 을 사용해서 매개변수로 받아와야 한다고 하더군요.. 큼!

그래서 받아왔고 변수 등록은 addAttribute 를 사용해서 해 주었답니다~~ (뿌듯)

그럼 이렇게 제가 설정한 이름으로 뜹니다~

 

/hi 페이지의 실행 흐름

1. 파일이 컨트롤러임을 선언

2. 클라이언트로부터 "/hi" 요청을 받아 접수

3. 요청을 받음과 동시에 niceToMeetYou() 메서드 수행

4. 변수 등록을 위해 모델 객체를 매개변수로 가져옴

5. 사용할 변수 등록 : 변수가 달라짐에 따라 서로 다른 뷰 템플릿 페이지 출력

6. greetings.mustache 파일 반환! : return 에는 파일 이름만 작성~

 

/bye 페이지도 직접 만들어 보았습니닷! 똑같은 흐름으로 작동하구, 코드도 비슷했습니당. ( ˃ᴗ˂ )

 

레이아웃이란?

- 화면에 요소를 배치하는 일!

- 헤더와 푸터 레이아웃이 가장 기본이 되는 레이아웃!

부트스트랩이란?

- 웹 페이지를 쉽게 만들 수 있도록 작성해 놓은 코드 모음!

 

헤더-푸터 레이아웃을 /hi 페이지와 /bye 페이지에 적용해 보았어요!

부트스트랩에서 코드를 가져왔고 처음에는 그냥 코드 전부를 greetings.mushache 에 붙여넣었는데 가독성이 너무 떨어지더라구요ㅠㅠ

그래서 이것을 템플릿화했어야 하는데요 바로 이게 무엇이냐 하면 ~~

- 코드를 하나의 틀로 만들어 변수화한다는 말입니다.

리액트로 치면 컴포넌트와 비슷한 개념일까요... 🤔 

그래서 { { >header } }, { { >footer } } 이런 식으로 불러와 주는 거예요!

그래서 header.mustache, footer.mustache 파일을 만들어서 코드를 작성해준 후 그대로 가져왔더니 훨씬 가독성 좋은 코드가 되었습니다~ 야호!! ( ˆoˆ )

 

폼 데이터란?

- HTML 요소인 <form> 태그에 실려 전송되는 데이터!

DTO 란?

-  폼 태그에 실어 보낸 데이터 서버의 컨트롤러가 객체에 담아 받는데 이 객체가 바로 DTO!

<form class="container" action="/articles/create" method="post">
</form>

 

여기서 action 은 어디에 보낼지 즉, URL 연결 주소를 적습니닷. 그리고 method 는 어떻게 보낼지 결정합니다.

 

제가 방금 실습한 코드의 결과값입니다!

너무... 갑자기라.. 살짝 당황스러우시겠지만 흐흐....

{{>layouts/header}}

<form class="container" action="/articles/create" method="post">
    <div class="mb-3">
        <label class="form-label">제목</label>
        <input type="text" class="form-control" name="title">
    </div>
    <div class="mb-3">
        <label class="form-label">내용</label>
        <textarea class="form-control" rows="3" name="content"></textarea>
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
</form>

{{>layouts/footer}}
package com.example.firstproject.controller;

import com.example.firstproject.dto.ArticleForm;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class ArticleController {
    @GetMapping("/articles/new")
    public String newArticleForm() {
        return "articles/new";
    }

    @PostMapping("/articles/create")
    public String createArticle(ArticleForm form) {
        System.out.println(form.toString());
        return "";
    }
}
package com.example.firstproject.dto;

public class ArticleForm {
    private String title;
    private String content;

    public ArticleForm(String title, String content) {
        this.title = title;
        this.content = content;
    }

    @Override
    public String toString() {
        return "ArticleForm{" +
                "title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

 

요약하자면!

뷰 페이지(new.mustache) 를 만들고 폼 태그의 action 속성으로 데이터를 어디로 보낼지! 저는 /articles/create 로 해 줬습니다. method 속성으로 데이터를 어떻게 보낼지 저는 post 로 ! 했습니다.

그리고 컨트롤러를 만들고, PostMapping 방식으로 URL 주소를 연결합니다.

전송 받은 데이터를 담아둘 객체인 DTO 를 만들어줬구요! 컨트롤러에서 폼 데이터를 전송 받아 DTO 에 담았습니다!~!

 

JPA란?

- DB 를 자바로 명령 내릴 수 있게 도와주는 도구예요!

엔티티란?

- 자바 객체를 DB 가 이해할 수 있게 만든 것으로, 이를 기반으로 테이블이 만들어진다!

리파지터리란?

- 엔티티가 DB 속 테이블에 저장 및 관리될 수 있게 하는 인터페이스!

의존성 주입이란?

- @Autowired 어노테이션을 붙이면 스프링 부트가 미리 생성해 놓은 객체를 가져다 연결해 준다!

Crud레포지토리란?

- JPA 에서 제공하는 인터페이스로 이를 상속해 엔티티를 관리할 수 있는 것

 

 

지금 이걸 출력하기 위해 많은 에러를 거쳐왔습니다ㅠㅠ

코드는 직관적이라서 이해가 잘 가는데 차근차근 진행하다 보니까 에러가 나는 부분이 있고 그 부분을 고치는 게 저는 어려웠습니다. ㅎㅎ

아직은 정확히 이해하지 못해서 설명은 어렵지만 어떤 느낌인지만 설명 하자면,

아이디를 대표 값으로 받고 값을 서로 주고 받으면서 엔티티로 변환 하고 그걸 DB에 저장 하는 과정! 입니다.

몇 번 더 책을 보면서 복습을 해야 할 것 같아요.. 한 번에 이해 하지 못해 속상하네요 ˶ˊᜊˋ˶ᐝ그래도 어떻게 사람이 한 번에 이해 하겠어요ㅠ 그럼 천재니까... 차근차근 해야죠!!!

 

 

지금 제가 한 것은 DB 데이터를 조회하는 것인데요!저는 DB를 배워 본 경험이 있기 때문에 딱히 설명을 하지 않겠지만 아까 만들어줬던 페이지에서 정보를 넘겨 온 것입니다.위에서 SQL문을 작성 해 주면 레코드가 삽입 될 수 있습니다. ⌯ᵔ⤙ᵔ⌯

 

롬복이란?

- 코드를 간소화해 주는 라이브러리

로깅이란?

- 프로그램의 수행 과정을 기록으로 남기는 것

리팩터링이란?

- 코드의 기능에는 변함 없이 코드의 구조 또는 성능을 개선하는 작업

 

롬복을 깔았더니!!!!

@AllArgsConstructor 가 생성자의 코드를 대신 해 주고, @ToString 이 toString 의 긴 메서드 문장을 대신해 줍니다.

우와!!! 이런 꿀팁이.. 대박 신기합니닷!!! ദ്ദി ( ᵔ ᗜ ᵔ )

 

실제로 개발을 할 때는 println() 문을 절대로 사용하면 안 됩니다!!!

- 기록에 남지도 않고 오히려 서버에 성능에도 악영향을 끼칩니다. 그렇기 때문에 사용하는 것이 로깅 기능입니다!

@Slf4j 는 Simple Logging Facade for Java 의 약자로 이 어노테이션을 추가해 주면 로깅 기능이 사용가능합니다 ~

여기서 방금 또.. 에러가 나서..... 롬복 플러그인으로 설치하구 왔습니다.

log.info(form.toString());

 

이렇게 작성을 해 주면!

 

이렇게 시간 정보와 함께 보이게 됩니다.

println() 을 사용했을 때는 일회성으로만 사용 되고 없어졌는데 로그로 찍었더니 이렇게 기록으로 남길 수 있습니다!

 

데이터의 조회 과정으로는

사용자가 데이터를 조회 해 달라고 웹페이지에서 URL 요청을 보내면~

서버의 컨트롤러가 요청을 받아 해당 URL 에서 찾으려는 데이터 정보를 리포지토리에 전달 합니다!

리포지토리는 정보를 가지고 DB에 데이터 조회를 요청 합니다.

DB는 해당 데이터를 찾아 엔티티로 반환하고 반환된 엔티티는 모델을 통해 뷰 템플릿으로 전달 됩니다.

이것이 사용자의 화면을 출력 됩니닷!!

 

만약 자신이 id 로 어떤 값을 출력 시키고 싶다면 GetMapping 으로 받아오면 됩니다!

@GetMapping("/articles/{id}")

 

이때 id 는 변수이며, 중괄호 하나만 써주면 됩니다!

그리고 여기서 @PathVariable 이라는 어노테이션을 사용할 것인데 이게 무엇이냐!

- URL 요청으로 들어온 전달값을 컨트롤러의 매개변수로 가져오는 어노테이션입니다~ ˆ ⩌ ˆ

public String show(@PathVariable Long id) {
    log.info("id = " + id);
    return "";
}

 

이렇게 코드를 작성해 주고 매개변수로 id 를 받아주면 됩니닷!

서버에서 아이디가 1000인 값이 없더라도 로그에는 id 값이 1000이라고 잘 찍히게 됩니다!

 

이제 데이터를 조회해 출력해 보겠습니닷.

// 1. id 를 조회해 데이터 가져오기
Article articleEntity = articleRepository.findById(id).orElse(null);

 

처음에 이렇게 작성해 줍니다. 만약 id 값을 찾았는데 없으면 null 을 리턴해 준다는 의미입니다. (っ ‘ ᵕ ‘ c)

 

그 다음은 articleEntity 에 담긴 데이터를 모델에 등록해 보겠습니다.

이는 MVC 패턴에 따라 조회한 데이터를 뷰 페이지에 사용하기 위해서 합니다!

model.addAttribute("article", articleEntity);

 

위에서 했던 방식과 동일하게 추가해 주면 됩니다!

 

반환할 페이지를 만들어주고 return 에 넣어준 후, 똑같이 mustache 파일을 만들어주고 부트스트랩에서 원하는 코드를 가져온 후 필요없는 코드는 다 지우고, 원하는 값만 출력할 수 있도록 합니다.

{{#article}}
<tr>
    <th>{{id}}</th>
    <td>{{title}}</td>
    <td>{{content}}</td>
</tr>
{{/article}}

 

여기서 이런 코드를 작성해 주었는데유~

모델에서 등록한 article 뷰 페이지에서 머스테치 문법인 이중중괄호를 사용해 출력합니닷!

#article 태그는 시작 태그와 닫는 태그가 있는데요! 어디에서 어디까지 사용할지 범위를 정합니다! (*˘◡˘*)

그리고 id, title, content 를 중중괄호를 통해 가져옵니다!

처음에는 데이터가 휘발성이기 때문에 서버를 재시작 할 때마다 데이터가 날아가서 값이 안 나오는데요!

롬복을 통해 기본 생성자를 Article.java 파일에 추가해 주게 되면 제가 값을 넣으면 해당 id 번호로 값을 가져올 수 있게 됩니다!!!

짜라란

 

다음은 데이터 목록을 조회하는 건데요!

단일 데이터를 조회할 때는 레포지토리가 엔티티를 반환했다면, 데이터 목록을 조회할 때는 엔티티의 묶음인 리스트를 반환합니닷!!

결과는 잘 나왔지만 몇 가지 짚고 넘어가야할 게 있습니다.

ArrayList<Article> articleEntityList = articleRepository.findAll();

 

우선 이 코드를 작성할 때까지 에러가 있었는데요~

이 에러를 고칠 수 있는 방법은 여러 개가 있었습니다! 바로 업캐스팅과 다운캐스팅을 통해 에러를 해결하는 방법인데요!

저희는 그냥 findAll 메서드를 ArrayList 반환값으로 수정해 주었습니닷!

업캐스팅과 다운캐스팅은 꼭 유의해서 알아두셔야 하구요, 값을 넣고 반환하는 방법은 똑같습니다!

 

또 여기서 중요한 점이 하나 더 있습니다!

{{#articleList}}
    <tr>
        <th>{{id}}</th>
        <td>{{title}}</td>
        <td>{{content}}</td>
    </tr>
{{/articleList}}

 

이 코드가 있는데요!

지금 저희가 리스트 묶음이 변수로 들어갔기 때문에 내부 코드가 반복됩니다!

저희는 총 3개의 값을 넘겨 줬으므로 id 가 1일 때 돌고, 2일 때 돌고, 3일 때도 돕니다!

마치 for 문과 같은 느낌이라고 생각하시면 좋습니다. (●⌒∇⌒●)


중간중간 마다 있는 셀프 체크도 풀고, 마무리 단원도 읽어서 공부가 열심히 된 것 같습니다!

저번 주에 조금 바빴어서 오늘 하루 만에 공부하려고 하니.. 장정 5시간이 걸렸군요.... 아직 풀지 못한.. 셀프체크 문제가 있어서 그것들을 다 풀고 정리하려고 합니다!!!

저의 이 정리가 나중에 도움이 될 수 있길~~ (▰˘◡˘▰)