[Spring Boot] (1) Spring Boot란?, 기본적인 Controller, View, Model의 사용
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이 아님을 검증 |
~ 참고한 자료 ~