개발일기/Java - Spring Boot

[Spring Boot] (1) Spring Boot란?, 기본적인 Controller, View, Model의 사용

Yoon Yusang 2025. 5. 12. 14:22
 

Spring Boot란?

 

Spring Boot와 MVC 모델

 

- MVC모델 : 어플리케이션 혹은 프로젝트를 구성할 때 그 구성요소를 세 가지의 역할(Model, View, Controller)로 구분하는 것.

- 사용자가 Controller를 조작하면, Controller는 Model을 통해 데이터베이스에 접근하고, 그 정보를 바탕으로 View가 시각적으로 표현하여 사용자에게 전달한다.

- Spring Boot를 통해 Controller와 Model을 간단히 구현할 수 있고, View는 Thymeleaf를 통해 구현하게 된다.

 

* Thymeleaf 란?

- Spring Boot에서 사용되는 템플릿 엔진으로, Spring Boot를 거치지 않고도 HTML의 편집이 가능해 코딩하기 편하고, 브라우저 상에서 직접 HTML을 열어볼 수 있어 디자이너로 개발 작업에 들어가기 편하다.

 

Spring Boot의 특징

 

1. POJO 프로그래밍 지향

- POJO : 순수하게 Java만을 통해 생성한 객체

- 외부 라이브러리나 외부 모듈을 사용하지 않고, Java 및 Java의 스펙에 정의된 기술만 사용한다.

- 외부 기술을 사용하고 있는 경우, 그 기술의 업데이트에 따라 객체들의 코드를 바꿔주어야 하나, POJO만으로 설계된 코드의 경우엔 외부 변화에 영향을 받지 않아 유연하게 변화와 확장에 대처할 수 있다.

- 또한, 객체지향 설계를 제한없이 적용할 수 있고 코드가 단순해져 테스트 및 디버킹이 쉬워진다.

 

2. IoC / DI (제어 역전 / 의존성 주입)

- IoC (제어 역전) : 개발자가 직접 객체를 생성하지 않고 외부 컨테이너 (Spring의 IoC Container)에서 객체를 관리/제어하는 것.

- DI (의존성 주입) : 제어 역전의 방법 중 하나로, 사용할 객체를 직접 생성하지 않고 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식.

- 제어 역전을 통해 개발자는 객체의 제어권을 컨테이너에 맡기고, 객체 관리 이외의 로직에만 집중할 수 있게 된다.

- 또한, 객체 간의 의존적인 연결이 약해짐으로써 보다 수정이나 변화에 있어 더 유연한 구조로 만들 수 있다.

- 다양한 방식으로 의존성 주입을 실현할 수 있으나, 생성자를 통한 의존성 주입이 권장되고 있다.

 

3. AOP (관심/관점 지향 프로그래밍)

- AOP (관심/관점 지향 프로그래밍) : 어떤 기능을 구현할 때, 각 기능을 '핵심 기능'과 '부가 기능' 으로 구분해 각각 하나의 관점에서 개발하는 것.

- 예를 들어, 회원 가입, 회원 정보 수정, 회원 탈퇴의 기능을 구현한다고 할 때, 각각은 핵심 기능으로써 구현하게 되나, 그 안에서 공통적으로 로깅이나 보안 관련된 코드가 포함되게 된다. 이와 같이 핵심 기능들에 공통적으로 구현되어야 하는 부가 기능과 관련된 코드들은 별도의 객체로 분리하여 그 객체의 메소드로 구현해주면 코드의 재사용이 용이해지고, 코드의 중복을 피할 수 있다.

 

4. PSA (일관된 서비스 추상화)

- PSA (일관된 서비스 추상화) : 특정 기술과 관련된 서비스를 추상화하여 일관된 방식으로 사용될 수 있도록 한 것.

- JDBC : Spring이 제공하는 인터페이스로, 데이터베이스 서비스를 추상화한 인터페이스. 이를 기반으로 데이터베이스 접근 코드를 작성하면, 개발 중에 데이터베이스를 바꾸더라도 기존의 데이터베이스 접근 로직을 그대로 사용할 수 있다.

 

 

Spring Boot 프로젝트 만들기

 

1. <파일 - 신규 - Spring스타터 프로젝트> 로 프로젝트 생성

2. 의존관계 설정 - 필요에 따라 사용할 기능을 추가해준다.

3. src/main/java/com/example/demo 아래에 Controller로 쓸 자바 파일을 생성

4. src/main/resources/templates 아래에 View로 쓸 HTML 파일을 생성

5. src/main/resources/static 아래에 외부 리소스 파일 생성/이동

+ <윈도우-뷰 표시-Boot대시보드> Boot배시보드 패널을 띄워놓는다.

 

* 앞으로의 프로젝트에서 자주 쓸 기능

- H2 Database : 자바 상에서 움직이는 인메모리 데이터베이스. 메모리 상에서 기동되기 때문에 기동될 때마다 초기화된다.

- JDBC API : 데이터베이스 서비스를 이용하기 위한 인터페이스

- Validation : 데이터 검증 기능

- Thymeleaf : HTML 편집을 위한 템플릿 엔진

 

 

 

기본적인 Controller, View, Model의 사용

 

Controller와 View를 통해 'Hello World' 출력하기

 

- SampleController.java에서 변수에 값을 지정하고, index.html에서 그 값을 사용하는 방식으로 진행한다.

 

1. SampleController.java

// Controller 클래스임을 명시
@Controller
public class SampleController{

    // 도메인 아래가 "/sample"인 URL로 액세스되었을 때 호출될 메소드
    @RequestMapping("/sample")
    public String sample(Model model){
    
        // "message"라는 변수에 "Hello World!"를 저장.
        // -> 이후 반환값인 index.html에서 message변수를 사용한다.
    	model.addAttribute("message", "Hello World!");
        
        // index.html을 호출
        return "index";
    }
}

 

2. index.html

<!DOCTYPE html>
// Thymeleaf를 사용하겠다는 선언
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title></title>
        <meta charset="utf-8"/>
    </head>
    <body>
    
        // h1태그 안의 문자열을 Controller로부터 전달받은 "message"로 설정.
        <h1 th:text="${message}"></h1>
    </body>
</html>

- th: : Thymeleaf를 사용하겠다는 것을 명시

- ${} : Controller로부터 전달받은 변수를 표시

 

3. 실행할 때는 Boot대시보드에서 프로젝트 선택 후, 패널 위쪽의 실행 버튼 클릭.

4. localhost:8080 으로 접속.

 

 

Thymeleaf 기본 문법 - 외부 리소스 사용

- 외부 리소스는 모두 src/main/resources/static 아래에 넣어둔다.

// 자바 스크립트 파일을 가져오는 경우
<script src="main.js" th:src="@{/main.js}></script>

// CSS 파일을 가져오는 경우
<link rel="stylesheet" href="style.css" th:href="@{/style.css}>

// 이미지 파일을 가져오는 경우
<img src="sample.jpg" th:src="@{/sample.jpg}>

- @{} : URL지정.

 

 

Thymeleaf 기본 문법 - 페이지 전이

<a href="input.html" th:href="@{/form}">화면 이동</a>

- 디자이너와의 협업을 위해 이런 식으로 작성을 하는 경우가 많다.

- 빌드 전에는 input.html로 바로 이동하고, 빌드 후엔 Spring Boot를 통해 form.html로 이동한다.

- 두 경우 모두 문제없이 작동되어야 하며, 디자이너는 빌드 전의 경우로, 프로그래머는 빌드 후의 경우로 작업한다.

 

 

Controller, View, Model을 통해 사용자로부터 입력받기

- input.html에서 사용자로부터의 입력을 Controller.java가 Form.java 클래스에 저장하고, 이후 그 클래스에 저장된 변수값을 confirm.html에서 확인할 수 있도록 하는 코드이다.

 

1. Form.java

public class Form{
    // 사용할 변수
    private String name;
    
    // 생성자
    public Form(){}
    
    // getter와 setter함수
    public String getName(){
    	return name;
    }
    public void setName(String name){
        this.name=name;
    }
}

- 사용자 입력을 저장할 클래스이다. 

- getter/setter 함수를 통해 Spring이 이 클래스의 변수에 접근한다.

 

2. SampleController.java

@RequestMapping("/form")
public String form(Model model, Form form){
    model.addAttribute("title", "샘플 폼");
    return "input";
}

@RequestMapping("/confirm")
// 매개변수로 데이터를 저장할 클래스를 두어야 하고,
// 매개변수명은 클래스명을 소문자로 설정해야한다.
public String confirm(Model model, Form form){
    model.addAttribute("title", "확인 페이지");
    return "confirm";
}

- 매개변수로 Form 클래스를 넣어주는 것만으로 Spring이 알아서 값을 넘겨준다.

 

3. input.html

// action='#' : 현재 페이지로 이동
// th:action="@{/confirm}" : /confirm으로 이동
<form method="get" action="#" th:action="@{/confirm}" th:object="${form}">

    // name이라는 이름으로 값을 저장해 전달.
    <p>이름 : <input type="text" name="name" th:value="*{name}"></p>
    <input type="submit" value="제출">
</form>

- action='#' : 다른 페이지로 이동하지 않고, 현재 페이지로 이동한다.

- ${} : Controller로부터 전달받은 변수를 쓸 때 사용하며, 오브젝트에도 마찬가지로 사용할 수 있다.

- *{} : 상위 태그의 오브젝트의 멤버변수에 액세스한다.

 

4. confirm.html

// 방법 1 : Controller.java의 form 오브젝트로부터 name 변수값을 불러온다.
<p th:text="${form.name}"></p>

// 방법 2 : form 오브젝트를 가져와, 그 안의 변수값을 불러온다.
// 오브젝트 안의 변수값을 여러 개 사용해야 할 때 편하다.
<div th:object="${form}">
    <p th:text="*{name}"></p>

 

5. confirm.html 내용 추가

// 입력 화면으로 돌아갈 경우.
<form method="get" action="#" th:action="@{/form}">
    // hidden으로 값을 저장해놓고 입력화면으로 돌아가는 버튼이 눌리면 값을 전달.
    <input type="hidden" name="name" th:value="*{name}">
    <input type="submit" value="입력 화면으로 돌아가기">
</form>

// 완료 화면으로 갈 경우
<form method="get" action="#" th:action="@{/complete}">
    <input type="hidden" name="name" th:value="*{name}">
    <input type="submit" value="완료 화면으로">
</form>

- 현재 페이지에서 새로 사용자 입력을 받지 않고 값을 전달하는 경우, hidden타입의 input을 이용한다.

 

 

Validation (데이터 검증)

- 사용자 입력 등으로 오브젝트에 데이터를 넣었을 때, 그 데이터가 유효한지 아닌지 검사를 할 수 있다.

 

1. Form.java

// 다양한 어노테이션을 통해 변수값 입력에 제한을 둘 수 있다.
// message를 통해, 유효하지 않은 입력일 경우 출력할 텍스트를 지정할 수 있다.
@Size(min=1, max=10, message="글자수 제한(1~10글자)를 지켜주세요."
private String name;

 

2. SampleController.java

@RequestMapping("/confirm")
// 인수의 순서가 바뀌면 안된다.
// Validation을 한 뒤, 그 결과값을 전달받음
public String confirm(@Validated Form form, BindingResult result, Model model){
    // Validation 결과, 에러가 있을 경우
    if(result.hasErrors()){
        return "input";
    }
    return "confirm";
}

 

3. input.html

<form method="get" action="#" th:action="@{/confirm}" th:object="${form}">
    <p> 이름 : <input type="text" name="name" th:value="*{name}"></p>
    
    // th:if : 조건분기. 여기선 에러가 있는지 확인
    // th:errors : 해당 멤버의 에러 메세지를 출력
    <div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
    <input type="submit" value="제출">
</form>

- th:if="${#fields.hasErrors('필드명')}" : 해당 필드의 에러 유무를 검사한다.

- th:errors="*{name}"> : 해당 필드의 에러 메세지를 출력한다.

 

* Validation 글로벌 설정

- src/main/resources의 application.properties 파일을 변경함으로써 설정할 수 있다.

javax.validation.constraints.NotBlank.message=필수입력입니다.
javax.validation.constraints.Size.message=글자수 1~10 이내로 입력해주세요.

 

* 자주 쓸만한 Validation 어노테이션

@AssertTrue / @AssertFalse 참/거짓 검증
@Past / @Future 과거 날짜/ 미래 날짜 검증
@Max / @Min 수치의 최대/최소값 설정
@Range(min = , max = ) 수치가 범위 내에 있는지 검증
@NotNull Null이 아님을 검증
@Pattern(regex = , flag = ) 지정한 정규표현식을 만족하는지 검증
@Size(min = , max = ) 문자열의 문자 수, 혹은 컬렉션 등의 갯수가 범위 내에 있는지 검증
@Length(min = , max = ) 문자열의 문자 수가 범위 내에 있는지 검증
@CreditCardNumber 신용카드 번호인지 검증
@NotBlank 공백문자 혹은 Null이 아님을 검증

 

 

~ 참고한 자료 ~

스프링과 스프링부트(Spring Boot)ㅣ정의, 특징, 사용 이유, 생성 방법

[Spring / 스프링 부트 핵심 가이드] 제어의 역전(IoC, DI, AOP)