Back-End (Web)/Spring

[Spring] Server에서 Client로 Data를 전달하는 방법

JABHACK 2024. 12. 19. 15:27

정적 리소스

📌 웹 애플리케이션에서 변하지 않는 파일들을 의미한다. 예를 들어, HTML, CSS, JavaScript, 이미지 파일들(JPG, PNG, GIF) 등이 정적 리소스에 해당한다.

  • 정적인 HTML, CSS, JS, Image 등을 변경 없이 그대로 반환한다.

 

정적 리소스의 특징

  1. 고정된 내용:
    • 요청이 올 때마다 동일한 콘텐츠를 제공합니다.
    • 실행되거나 동적으로 변환되지 않습니다.
  2. 캐싱 가능:
    • 정적 리소스는 자주 요청되므로 브라우저에서 캐싱하여 성능을 최적화할 수 있습니다.
  3. 서버 부담 감소:
    • 서버는 정적 리소스를 변환하거나 처리하지 않으므로, 부하가 적습니다.
  4. 브라우저에서 직접 렌더링:
    • 클라이언트(브라우저)가 직접 처리할 수 있는 파일 형식으로 제공됩니다.

 

 

Spring Boot에서 정적 리소스 제공

  • Spring Boot는 기본적으로 정적 리소스를 제공하기 위한 구조를 내장하고 있습니다.

1. 정적 리소스 경로

Spring Boot는 다음 디렉토리에서 정적 리소스를 자동으로 로드합니다:

디렉토리 설명
/static src/main/resources/static에 있는 파일을 정적 리소스로 제공.
/public src/main/resources/public에 있는 파일을 정적 리소스로 제공.
/resources src/main/resources에 있는 파일.
/META-INF/resources JAR 파일의 META-INF 디렉토리 내부의 파일.

 

2. 정적 리소스 예제

 

 

 

정적 리소스와 동적 리소스 비교

  정적 리소스 동적 리소스
변경 여부 고정된 콘텐츠 (HTML, CSS, JS, 이미지 등). 요청에 따라 내용이 동적으로 생성됨.
처리 방식 서버가 파일 그대로 응답. 서버가 요청 데이터를 처리하여 응답 생성.
요청-응답 속도 빠름 (파일 그대로 반환). 비교적 느림 (처리 후 반환).
예시 HTML, CSS, JS, 이미지 파일. REST API 응답, 템플릿 엔진 출력.

 

 

정적 리소스와 컨트롤러 경로 충돌

Spring Boot는 기본적으로 정적 리소스를 우선 처리합니다.
예:

  • /index.html 정적 파일이 있으면, 해당 파일을 반환.
  • /index를 처리하는 컨트롤러가 있다면, 정적 리소스 대신 컨트롤러가 처리.

컨트롤러 우선 처리

application.properties에서 다음 설정으로 컨트롤러를 우선 처리하도록 변경 가능합니다:

spring.mvc.static-path-pattern=/**

 

 

정적 리소스 최적화

  1. Gzip 압축:
    • 정적 리소스를 Gzip으로 압축하여 전송 속도를 개선.
    properties
     
     
  2. Content Delivery Network (CDN):
    • 정적 리소스를 CDN에 배포하여 전 세계적으로 빠르게 제공.
  3. 캐싱:
    • 브라우저 캐싱을 활용하여 불필요한 네트워크 요청을 줄임.
server.compression.enabled=true
server.compression.mime-types=text/html,text/xml,text/plain,text/css,application/javascript

 

 

요약

  • 정적 리소스는 서버가 변경 없이 그대로 반환하는 콘텐츠입니다.
  • Spring Boot는 /static, /public 등 기본 경로에서 정적 리소스를 자동으로 제공합니다.
  • 정적 리소스는 속도가 빠르고 서버 부하가 적으므로, 이미지, CSS, JS 등의 파일 전송에 최적입니다.
  • 필요 시 경로와 캐싱 설정을 커스터마이징할 수 있습니다.
  • Spring Boot의 정적 리소스 경로
    • 아래 경로들에 정적 리소스가 존재하면 서버에서 별도의 처리 없이 파일 그대로 반환된다.
    1. /static
    2. /public
    3. /META-INF/resources
    4. src/main/resources
      1. /static

Spring Boot Directory 구조

  • src/main/resources/static/hello/world.html 디렉토리 구조라면
    • http://localhost:8080/hello/world.html URL로 리소스에 접근이 가능하다.
    • /static 대신 /public 혹은 /META-INF/resources 도 사용 가능하다.

 

View Template (동적 리소)

📌 웹 애플리케이션에서 서버가 클라이언트에 응답으로 제공할 HTML 페이지를 동적으로 생성하기 위해 사용하는 템플릿 파일입니다. 데이터를 표시하기 위해 동적인 콘텐츠와 정적인 HTML 구조를 결합하는 데 사용됩니다.

  • Spring에서는 Thymeleaf, JSP와 같은 템플릿 엔진을 사용해 View Template을 작성할 수 있고, View Template은 서버에서 데이터를 받아 이를 HTML 구조에 맞게 삽입한 후, 최종적으로 클라이언트에게 전송되는 HTML 문서로 변환하여 사용자에게 동적으로 생성된 웹 페이지를 제공한다.
  • 📌 View Template
    • View Template은 Model을 참고하여 HTML 등이 동적으로 만들어지고 Client에 응답된다.
    • Spring Boot는 기본적으로 View Template 경로(src/main/resources/templates)를 설정한다.
    • build.gradle에 Thymeleaf 의존성을 추가하면 ThymeleafViewResolver와 필요한 Spring Bean들이 자동으로 등록된다. 
  • SSR(Server Side Rendering)을 사용할 때 View가 반환된다.

View Template의 역할

  • 정적 HTML과 동적 데이터 결합:
    • 서버에서 HTML 파일에 동적 데이터를 삽입하여 사용자 맞춤 콘텐츠를 생성.
  • 서버 사이드 렌더링 (SSR):
    • 브라우저에 표시될 HTML을 서버에서 렌더링하고 클라이언트로 전송.
  • UI 레이아웃 관리:
    • 레이아웃, 반복 구조, 조건부 표시 등과 같은 동적 UI 요소를 효율적으로 관리.

 

Spring MVC에서 View Template

Spring MVC에서는 Model-View-Controller 패턴을 기반으로 View Template 엔진을 사용하여 HTML을 생성합니다.

Spring MVC에서의 동작 흐름

  1. Controller:
    • 클라이언트의 요청을 처리하고, 데이터를 Model 객체에 담아 View로 전달.
  2. View Template:
    • Model 데이터를 기반으로 HTML을 렌더링.
  3. Client:
    • 완성된 HTML 페이지를 클라이언트로 전송하여 브라우저에 표시.

 

pring Boot에서 지원하는 View Template 엔진

Thymeleaf Spring Boot에서 가장 널리 사용되는 템플릿 엔진. 자연스러운 HTML과의 통합 제공.
JSP Java 기반의 전통적인 템플릿 엔진. Servlet Container에서 실행.
Freemarker 강력한 기능의 템플릿 엔진. 다양한 커스터마이징 가능.
Mustache 간단하고 가벼운 템플릿 엔진. JavaScript에서도 동일 문법 사용 가능.
Groovy Templates Groovy 언어 기반의 템플릿 엔진.

 

 

Thymeleaf 예제 (Spring Boot 기본 설정)

a. Maven 의존성 추가

Spring Boot Starter를 사용하면 Thymeleaf가 기본적으로 포함됩니다:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

 

b. 프로젝트 구조

 

c. Controller 코드

@Controller
public class HomeController {

    @GetMapping("/")
    public String home(Model model) {
        model.addAttribute("title", "Welcome to Thymeleaf");
        model.addAttribute("message", "Hello, Thymeleaf!");
        return "home"; // home.html을 렌더링
    }
}

 

d. Thymeleaf View Template (home.html)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title th:text="${title}">Default Title</title>
</head>
<body>
    <h1 th:text="${message}">Default Message</h1>
</body>
</html>

 

결과

  1. 클라이언트가 /로 요청.
  2. Controller가 Model에 데이터를 담아 home.html로 전달.
  3. Thymeleaf가 데이터를 HTML에 삽입.
  4. 클라이언트로 다음과 같은 HTML 응답이 전송:
<!DOCTYPE html>
<html>
<head>
    <title>Welcome to Thymeleaf</title>
</head>
<body>
    <h1>Hello, Thymeleaf!</h1>
</body>
</html>

 

 

@Controller의 응답으로 String을 반환하는 경우

  • @ResponseBody 가 없으면 View Resolver가 실행되며 View를 찾고 Rendering한다.
@Controller
public class ViewTemplateController {
	
	@RequestMapping("/response-view")
  public String responseView(Model model) {
      // key, value
      model.addAttribute("data", "sparta");

      return "thymeleaf-view";
  }
	
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>
    <h1>Thymeleaf</h1>
    <h2 th:text="${data}"></h2>
</body>
</html>

 

ex) http://localhost:8080/response-view

  • @ResponseBody 가 있으면 HTTP Message Body에 return 문자열 값이 입력된다.

Postman

 

반환 타입이 void인 경우

  • 잘 사용하지 않는다.
  • @Controller + (@ResponseBody, HttpServletResponse, OutputStream)과 같은 HTTP Message Body를 처리하는 파라미터가 없으면 RequestMapping URL을 참고하여 View Name으로 사용한다.
@Controller
public class ViewTemplateController {
	
	// thymeleaf-view.html 과 Mapping된다.
  @RequestMapping("/thymeleaf-view")
  public void responseViewV2(Model model) {
      model.addAttribute("data", "sparta");
  }
	
}

 

  • 예시와 같은 경우에는 viewTemplate(viewName)을 RequestMapping URL 주소로 찾는다.

 

 

HTTP Message Body

📌 HTTP Message Body는 HTTP 요청(Request) 또는 응답(Response)에서 실제 데이터를 담는 부분입니다.

  • REST API를 만드는 경우 Server에서 Client로 HTML을 전달하는 방식이 아닌 HTTP Message Body에 직접 Data를 JSON 형식으로 담아 전달한다.
  • 정적 HTML, View Template 또한 HTTP Message Body에 담겨서 전달된다. 현재 설명하는 Response의 경우는 정적 HTML, View Template을 거치지 않고 직접 HTTP Response Message를 만들어 전달하는 경우를 말하는것.

 

HttpServletResponse 사용

@Controller
public class ResponseBodyController {
	
	@GetMapping("/v1/response-body")
	public void responseBodyV1(
														HttpServletResponse response
													) throws IOException {
		
		response.getWriter().write("data");
	
	}
}

Postman

  • Response Body에 data 라는 문자열이 입력되어 응답된다.
  • 기존 Servlet을 다룰 때 코드와 형태가 같다.

 

ResponseEntity<> 사용

@GetMapping("/v2/response-body")
public ResponseEntity<String> responseBodyV2() {
		
	return new ResponseEntity<>("data", HttpStatus.OK);
}

Postman

  • Response Body에 data라는 문자열과 HttpStatus.OK에 해당하는 상태 코드를 반환한다.
  • ResponseEntity는 HttpEntity 를 상속받았다.
    • HttpEntity는 HTTP Message의 Header, Body 모두 가지고 있다.

 

@ResponseBody(TEXT, JSON) 사용

@Data
@NoArgsConstructor // 기본 생성자
@AllArgsConstructor // 전체 필드를 인자로 가진 생성자
public class Tutor {

    private String name;
    private int age;

}
// TEXT 데이터 통신
@ResponseBody
@GetMapping("/v3/response-body-text")
public String responseBodyText() {
		
	return "data"; // HTTP Message Body에 "data"
}

 

Postman

// JSON 데이터 통신
@ResponseBody
@GetMapping("/v3/response-body-json")
public Tutor responseBodyJson() {
		
	Tutor tutor = new Tutor("wonuk", 100);
		
	return tutor; // HTTP Message Body에 Tutor Object -> JSON
}

Postman

  • View를 사용하는 것이 아닌 HTTP Message Converter를 통해 HTTP Message Body를 직접 입력할 수 있다. → ResponseEntity와 같음
  • @ResponseStatus 를 사용하여 상태 코드를 지정할 수 있다.

 

@ResponseStatus(HttpStatus.OK)
@ResponseBody
@GetMapping("/v4/response-body")
public Tutor responseBodyV4() {
		
	Tutor tutor = new Tutor("wonuk", 100);
		
	return tutor;
}

Postman

  • 단, 응답 코드를 조건에 따라서 동적으로 변경할 수는 없다.

ex) 1번의 경우 OK, 2번의 경우 Created

 

 

ResponseEntity<Object>(JSON)

@ResponseBody
@GetMapping("/v5/response-body")
public ResponseEntity<Tutor> responseBody() {
		
	Tutor tutor = new Tutor("wonuk", 100);
	
	return new ResponseEntity<>(tutor, HttpStatus.OK);
}

Postman

  • ResponseEntity<>두 번째 파라미터에 Enum을 사용하여 상태 코드를 바꿀 수 있다.
  • HTTP Message Converter를 통하여 JSON 형태로 변환되어 반환된다.
  • 동적으로 응답 코드를 변경할 수 있다.
@ResponseBody
@GetMapping("/v5/response-body")
public ResponseEntity<Tutor> responseBody() {
		
	Tutor tutor = new Tutor("wonuk", 100);
	
	if (조건) {
		return new ResponseEntity<>(tutor, HttpStatus.OK);
	} else {
		return new ResponseEntity<>(tutor, HttpStatus.BAD_REQUEST);
	}
	
}
  • HttpEntity를 상속받았다.

 

 

 

정리

 

Client에서 Server로 Data를 전달하는 세가지 방법

  1. GET - Query Param, Query String

ex) http://localhost:8080/tutor?name=wonuk&age=100

  • 사용하는 어노테이션
    • @RequestParam, @ModelAttribute
  1. POST - HTML Form(x-www-form-urlencoded)
POST /form-data
content-type: application/x-www-form-urlencoded

**key1=value1&key2=value2**
  • 사용하는 어노테이션
    • @RequestParam, @ModelAttribute
  1. HTTP Request Body

ex) 데이터(JSON, TEXT, XML 등)를 직접 HTTP Message Body에 담아서 사용한다.

  • 사용하는 어노테이션
    • @RequestBody

 

 

Server(Spring)에서 HTTP 응답을 Client에 전달하는 세가지 방법

  1. 정적 리소스
    • 정적인 HTML, CSS, JS, Image 등을 변경없이 그대로 반환한다.

  1. View Template
    • SSR(Server Side Rendering)을 사용할 때 View가 반환된다.
    • 사용하는 어노테이션
      • @Controller
       

 

  1. HTTP Message Body
    • 응답 데이터를 직접 Message Body에 담아 반환한다.
    • 사용하는 어노테이션
      • @ResponseBody, ResponseEntity<Object>
       

 

  • 요청
    • @RequestParam, @ModelAttribute, @RequestBody
  • 응답
    • 정적 리소스, View Template(@Controller), @ResponseBody, ResponseEntity<Object>

'Back-End (Web) > Spring' 카테고리의 다른 글

[Spring] Layered Architecture  (2) 2024.12.20
[Spring] HTTP Message Body & TEXT  (0) 2024.12.18
[Spring] @RequestParam & @ModelAttribute  (0) 2024.12.17
[Spring] Request Mapping  (1) 2024.12.16
[Spring] Spring Annotation  (1) 2024.12.15