도서 'Spring in Action' 제 5판을 보고 책 내용과 그 이외의 부족한 부분을 채워가며 공부한 내용입니다.
키워드 : 스프링 애플리케이션 초기 설정, 스프링 웹 개발 방식, 스프링 MVC, Servlet
1. 스프링 애플리케이션 초기 설정
Spring Initializr
REST API를 사용하는 브라우저 기반의 웹 애플리케이션으로, 우리가 원하는 기능을 구현할 수 있는 스프링 프로젝트를 자동으로 만들어준다.
Spring Initializr를 이용하는 방법
- 스프링 스타터
- Intellij IDEA IDE를 사용한 새로운 프로젝트 생성
- Spring Tool Suite IDE를 사용해서 새로운 프로젝트 생성
※필자는 Spring Tool Suit IDEf를 사용
스프링 프로젝트의 구조
- mvnw 와 mvnw.cmd : 이 파일들은 메이븐 래퍼 스크립트로, 메이븐이 프로젝트를 빌드하는 데 쓰이는 파일
- pom.xml : 메이븐이 프로젝트를 빌드할 때 필요한 정보(명세)가 들어있는 파일
- TacoCloudApplication : 스프링 부트 메인 클래스
- application.properties : 프로젝트의 세부적인 구성 속성을 정의할 수 있는 파일
- static : 브라우저에 제공할 정적 콘텐츠(img, CSS, JavaScript 등)를 저장해놓는 폴더
- templates : 브라우저에 콘텐츠를 보여주는 템플릿 파일을 두는 폴더이다.
- TacoCloudApplicationTests.java : 스프링 애플리케이션이 성공적으로 로드되는지 확인하는 간단한 테스트 클래스
1. 빌드 명세(pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>sla</groupId>
<artifactId>taco-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>taco-cloud</name>
<description>Taco Cloud Example</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
<parent>요소의 <version>
- 우리 프로젝트가 부모 POM(Project Object Model)으로 spring-boot-starter-parent를 갖는다는 것을 지정
- 이 부모 POM은 스프링 프로젝트의 여러 라이브러리의 의존성 관리를 제공
- 스프링 부트의 버전만 기록하면 다른 라이브러리들의 버전을 지정할 필요가 없음(스프링 부트 버전에 의해 의존성 관리를 제공)
-
의존성 정의
-
프로젝트 위저드에서 선택한 각 의존성이 <dependency>요소로 지정
-
Spring Web, Thymeleaf, Spring Boot DevTools, Lombok
-
spring-boot-starter-test는 우리가 테스트를 작성할 것에 대비해 스프링 Initializr가 자동으로 추가
<artifactId>에 포함된 starter (artifactId = 프로젝트 ID)
- Spring Web, Thymeleaf, Test가 starter 포함
- 스프링 부트 starter 의존성을 나타냄
- starter 의존성
- 우리가 필요로 하는 모든 라이브러리의 의존성을 선언하지 않아도 되므로 빌드 파일이 훨씬 작아지고 관리가 편함
- 라이브러리의 이름이 아닌 기능의 관점으로 의존성 생각
- 라이브러리들의 버전을 걱정하지 않아도 됨.(스프링 부트의 버전만 신경쓰면 됨)
- starter 의존성
<plugins>
- 메이븐을 사용하는 애플리케이션을 실행
- 의존성이 있는 모든 라이브러리가 JAR파일에 포함되어 있는지 확인
- 런타임 시에 classpath를 찾을 수 있는지 확인
- 메인 부트스트랩 파일(TacoCloudApplication)을 나타내는 부트스트랩 파일을 JAR파일에 생성
2. 애플리케이션 부트스트랩(구동)
우리가 Spring Initializr로 스프링 프로젝트를 생성하면 생기는 main 클래스를 부트스트랩 클래스
여기서는 TacoCloudApplication.java가 될 것
해당 클래스에는 @SpringBootApplication 이라는 애노테이션이 붙어있음
- 부트스트랩(Bootstrap) : 한번 시작되면 알아서 진행되는 일련의 과정
-
실행 가능 JAR파일에서 애플리케이션을 실행
-
제일 먼저 시작되는 부트스트랩 클래스가 필요
TacoCloudApplication.java
package tacos;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TacoCloudApplication {
public static void main(String[] args) {
SpringApplication.run(TacoCloudApplication.class, args);
}
}
@SpringBootApplication
- @SpringBootConfiguration : 현재 클래스(TacoCloudApplication)를 구성 클래스로 지정
- @Configuration과 거의 유사한 애노테이션이며, 다른점은 @SpringBootConfiguration은 이 클래스의 패키지와 하위패키지의 모든 @Configuration(구성 클래스)을 탐색해서 빈(객체)로 등록
- @EnableAutoConfiguration : 스프링 부트 자동-구성을 활성화
- 즉, @ComponentScan으로 빈이 등록된 이후, 추가적인 Bean들을 읽어 등록하는 애노테이션
- 우리가 커스텀하게 등록한 빈 이외에 스프링이 필요로 하는 빈들을 자동으로 등록
- @ComponentScan : 컴포넌트 검색을 활성화
- @Component, @Controller, @Repository 등의 애노테이션이 붙어있는 클래스들을 자동으로 찾아 스프링 컨테이너에 컴포넌트로 등록
- 따로 기본 패키지를 설정하지 않는다면, 현재 부트스트랩 패키지를 포함한 하위 패키지에 있는 컴포넌트들을 모두 빈으로 등록
- 컴포넌트(빈) 객체로 등록하지 않을 애노테이션이나 추가적으로 등록할 커스텀 애노테이션을 추가할 수 있음
-
SpringApplication.run(TacoCloudApplication.class, args);
- 스프링 컨테이너를 시작하고 스프링 ApplicationContext 객체를 반환
추가적인 어노테이션 정리
-
@Component : 해당 클래스가 스프링에서 객체로 만들어서 관리하는 대상임을 명시하는 어노테이션
-
@ComponentScan을 통해 @Component 어노테이션이 있는 클래스들을 객체로 생성해서 빈으로 관리
-
-
@Autowired : 스프링 내부에서 자신이 특정한 객체에 의존적이므로 자신에게 해당 타입의 빈을 주입해달라는 표시
-
스프링은 @Autowired 어노테이션을 보고 스프링 내부에 관리되는 객체 중에서 적당한 것이 있는지 확인하고, 자동으로 주입
-
- @ContextConfiguration : 스프링이 실행되면서 어떤 설정 정보를 읽어 들여야 하는지 명시
- 속성으로는 XML 파일 또는 @Configuration 어노테이션이 적용된 클래스를 지정할 수 있음.
-
@Runwith : 테스트 시 필요한 클래스를 지정
-
스프링은 SpringJUnit4ClassRunner 클래스가 대상
-
-
@Test : JUnit에서 해당 메소드가 JUnit 상에서 단위 테스트의 대상임을 알려줌.
3. 웹 요청 처리(@Controller)
Controller
웹 요청과 응답을 처리하는 컴포넌트
웹브라우저 요청을 상대할 경우 컨트롤러는 선택적으로 모델데이터를 채워 응답하며 브라우저에 반환되는 HTML 을 생성하기 위해 응답의 웹요청을 뷰에 전달
@Controller
public class HomeController {
@GetMapping("/") // 루트 경로 / 의 웹 요청 처리
public String home() {
return "home"; // 뷰 이름 반환
}
}
※ View : src/main/resources/templates 에 html file 생성
4. Controller 테스트
@WebMvcTest(HomeController.class)
public class HomeControllerTest {
@Autowired
private MockMvc mockMvc; // MockMvc 주입
@Test
public void testHomepage() throws Exception {
mockMvc.perform(get("/")) // get 수행
.andExpect(status().isOk()) // HTTP 200 OK 리턴
.andExpect(view().name("home")) // home.html view
.andExpect(content().string(containsString("Welcome to..."))); // Welcome to... 텍스트 포함
}
}
- 메소드 체인 적용
- @SpringBootTest
- 스프링 부트 기능으로 테스트를 시작하라는 것을 JUnit에 알려줌
- JUnit : 개발자가 개발한 모듈들이 정상적으로 동작하고 원하는 결과를 만들어내는지 확인하는 테스트
- main 메서드의 SpringApplcation.run()의 호출에 부합되는 테스트 클래스
- 스프링 애플리케이션 컨텍스트를 로드하는 작업을 수행
- 스프링 부트 기능으로 테스트를 시작하라는 것을 JUnit에 알려줌
2. 스프링 웹 개발 방식
1. 정적 컨텐츠 : 파일 자체를 웹 브라우저에 전달
2. MVC와 템플릿 엔진 : server에서 html 파일을 변환 후 전달
3. API : xml이나 JSON(default)으로 client에게 전달, server끼리 통신할 때 사용
MVC와 템플릿 엔진
MVC
Model, View, Controller로 관점을 3가지 형태로 나눠 프로그래밍하는 디자인 패턴
Model은 '어플리케이션이 무엇을 할 것인지', View는 '화면에 보여주기 위한', Controller는 '모델이 어떻게 처리할지'에 대한 역할 수행
- Model
- View
- Controller
템플릿 엔진
DATA + Template을 가지고 Template Engine을 거쳐 Result Page가 나옴.
-
템플릿 양식과 특정 데이터 모델에 따른 입력 자료를 합성하여 결과 문서를 출력하는 소프트웨어
-
쉽게 말해 서버에서 동적으로 html을 변환하여 웹 브라우저로 보내주는 역할
-
텍스트 템플릿 엔진
- 템플릿 양식에 적절한 특정 데이터를 넣어 결과 문서를 출력(Thymeleaf, JSP)
- 종류
- 서버사이드 템플릿 엔진(Server Side Template Engine)
-
서버에서 DB 혹은 API에서 가져온 데이터를 미리 정의된 Template(미리 제작된 프레임)에 넣어 html을 그려서 클라이언트에 전달
-
즉, HTML 코드에서 고정적으로 사용하는 부분은 템플릿으로 만들어 두고 동적으로 생성되는 부분만 템플릿 소스코드에 끼워넣는 방식
-
- 클라이언트 사이드 템플릿 엔진(Client Side Template Engine)
-
HTML형태로 코드를 작성할 수 있음
-
동적으로 DOM(Document Object Model)을 그리게 해주는 역할
- DOM - HTML 요소들의 구조화된 표현
-
데이터를 받아 DOM 객체에 동적으로 그려주는 프로세스 담당
-
웹페이지에서 여러 카테고리 탭 중 하나를 선택할 때 같은 형식의 프레임(template)에 내용만 바뀌어 변경되는 것
-
- 서버사이드 템플릿 엔진(Server Side Template Engine)
MVC와 템플릿 엔진의 동작과정
-
웹 브라우저에서 localhost:8080/hi 를 요청
-
spring boot를 띄울 때 같이 띄우는 내장 tomcat 서버를 거치면서 tomcat 서버는 /hi 요청이 왔음을 spring에게 넘김
-
spring은 Controller에 /hi가 @GetMapping을 통해 hello-mvc가 mapping 되어 있는 것을 확인하고, mapping 되어있는 해당 메서드를 실행해당 메서드는 "hi-template"라는 String을 반환하고, Model에는 (key : name, value : spring)이라는 값을 넣는다. 그리고 이 값들을 spring에게 넘겨준다.
-
spring의 viewResolver가 동작한다. viewResolver는 View를 찾아주고, 템플릿 엔진을 연결시켜주는 역할을 한다.viewResolver가 templates/hi-template.html 을 찾아서 Thymeleaf 템플릿 엔진에게 처리 요청을 한다.
-
템플릿 엔진인 Thymeleaf가 렌더링해서 html로 변환한 후, 웹 브라우저에 반환한다.
3. Servlet
자바를 사용하여 웹을 만들기 위해 필요한 기술
자바로 구현된 CGI라고 알려짐
※ CGI(Common Gateway Interface)
특별한 라이브러리나 도구를 의미하는 것이 아니고, 별도로 제작된 웹 서버와 프로그램간의 교환방식
CGI방식은 어떠한 프로그래밍 언어로도 구현이 가능하며, 별도로 만들어 놓은 프로그램에 HTML의 Get or Post 방법으로 클라이언트의 데이터를 환경변수로 전달하고, 프로그램의 표준 출력 결과를 클라이언트에게 전송하는 것
특징
-
클라이언트의 요청에 대해 동적으로 작동하는 웹 어플리케이션 컴포넌트
-
html을 사용하여 요청에 응답
-
Java Thread를 이용하여 동작(서블릿 컨테이너는 멀테 쓰레드로 운용, 원래는 쓰레드의 생성을 관리해야 했지만 서블릿 컨테이너가 이를 대신 관리해줌)
-
MVC 패턴에서 Controller로 이용
-
HTTP 프로토콜 서비스를 지원하는 javax.servlet.http.HttpServlet 클래스를 상속
-
UDP보다 처리 속도가 느림
-
HTML 변경 시 Servlet을 재컴파일해야 하는 단점
Servlet의 동작 방식
-
사용자(클라이언트)가 URL을 입력하면 HTTP Request가 Servlet Container로 전송
-
요청을 전송받은 Servlet Container는 HttpServletRequest, HttpServletResponse 객체를 생성
-
web.xml을 기반으로 사용자가 요청한 URL이 어느 서블릿에 대한 요청인지 찾기
-
해당 서블릿에서 service메소드를 호출한 후 클리아언트의 GET, POST여부에 따라 doGet() 또는 doPost()를 호출
-
doGet() or doPost() 메소드는 동적 페이지를 생성한 후 HttpServletResponse객체에 응답
-
응답이 끝나면 HttpServletRequest, HttpServletResponse 두 객체를 소멸
추가정보
WAS(Web Application Server)
동적 요청을 처리(JVM, Tomcat)
-
httpServletRequest 객체 : 정보 뭉텅이(전달받은 데이터) -> 나중에 새로운 동적 페이지를 만들 때 사용
-
httpServletResponse 객체 : 빈 객체 -> 나중에 DB와 httpServletRequest의 데이터들로 만든 결과 페이지를 담아 WEB으로 다시 돌려보냄(즉, 결과물)
-
doGet(), doPost() : Web.xml에서 해당 요청을 처리하는 survlet에 doGet(), doPost()함수를 실행
- httpServletResponse를 WEB에 다시 보내면서 쓰레드는 사라짐
'Spring' 카테고리의 다른 글
Spring 데이터로 작업하기 1 (0) | 2022.05.18 |
---|---|
Spring 웹 애플리케이션 개발 3 (0) | 2022.05.11 |
Spring 웹 애플리케이션 개발 2 (0) | 2022.05.11 |
Spring 웹 애플리케이션 개발 1 (0) | 2022.05.11 |
Spring 기초 - 1 (0) | 2022.05.09 |