
- 지난과제 간단 정리
- http remind
- 웹서버와 WAS
- 서블릿
- 쓰레드 풀
- 정적 리소스와 동적 리소스
- 컨트롤러 와 http 메소드
- 디스패처 서블릿
- 총정리
- 김수환이 한 과제
: HyperText Transfer Protocol
| 이름 | 요청 예시 |
|---|---|
| start-line | GET /core/members/info?member_id=123 HTTP/1.1 |
| header | Host: www.helloLandVibe.com |
| ...etc | |
| empty line | |
| message body | {요청메시지 바디에 값 있을수 있음} |
| 이름 | 응답 예시 |
|---|---|
| start-line | HTTP/1.1 200 OK |
| header | Content-Type: text/json; |
| charset=UTF-8 Content-Length: 85 | |
| Date: Mon, 12 Aug 2024 12:00:00 GMT | |
| ...etc | |
| empty line | |
| message body | { |
| "member_id": 123, | |
| "name": "땅울림", | |
| "balance": 50000, | |
| "status": "active" | |
| } |
역할: 정적 리소스를 제공
예시:
사용자가 브라우저에서 www.helloLandVibe.com을 입력
웹 서버는 index.html 파일을 찾아서 클라이언트에게 전달
| 클라이언트(브라우저) | 서버(웹 서버) | |
|---|---|---|
| → | HTTP 요청 | |
| ← | HTTP 응답: index.html 파일 |
역할: WAS는 동적 콘텐츠를 생성하고 처리
예시:
사용자가 로그인 버튼을 클릭
WAS는 사용자 이름과 비밀번호를 데이터베이스에서 확인
로그인 결과에 따라 환영 메시지 또는 오류 메시지를 반환
| 클라이언트(브라우저) | 서버(WAS) | |
|---|---|---|
| → | HTTP 요청: 로그인 정보 | |
| ← | HTTP 응답: 환영 메시지 또는 오류 메시지 |
┌───────────┐ ┌────────────┐
│ 클라이언트 │──────▶│웹 서버 (정적) │
│ │ └────────────┘
└───────────┘ │
▼
┌────────────┐
│ WAS (동적) │
└────────────┘

백엔드의 역할
Front End 가 사용자에게 필요한 데이터를 편하게 받을 수 있게 도와준다면,
Back End 는 사용자가 필요한 데이터를 안전하게 저장하고, 필요한 비즈니스 로직을 통해 가공한 후, 요청에 맞게 제공 할 수 있어야 한다.
Java를 기반으로 웹 애플리케이션을 개발할 때 사용되는 서버측 컴포넌트
HTTP 요청을 처리하고 그에 대한 응답을 생성
응? 컨트롤러 아니야?
Controller
보통 MVC 패턴에서 사용되는 컴포넌트
- 클라이언트의 요청을 받아 처리한 후, Model을 통해 데이터를 처리, 뷰(View)를 통해 결과를 사용자에게 전달
- Spring 프레임워크 :
@Controller어노테이션을 사용Servlet VS Controller
- 서블릿:
- 더 낮은 레벨에서 동작
- 요청과 응답을 수동으로 처리
- 개발자가 모든 작업을 직접 처리해야 하므로, 코드가 복잡하다.
- 기능 확장이나 재사용이 제한적
- 컨트롤러:
- 서블릿을 기반으로 동작하지만, 더 높은 레벨의 추상화를 제공
- 프레임워크의 도움을 받아 개발이 더 편리
- 프레임워크가 많은 작업을 자동으로 처리
사실 서블릿이 전달 해주면 컨트롤러가 받는거임
디스패처 서블릿은 스프링 MVC에서 중앙 컨트롤러 역할을 수행하는 서블릿
서블릿을 관리하고, 생명 주기를 관리하며, 요청을 서블릿으로 전달하고 그 결과를 클라이언트에게 반환하는 역할을 수행하는 서버 환경.
Apache 재단에서 제공하는 오픈 소스 서블릿 컨테이너이자 WAS
자바 서블릿과 JSP(JavaServer Pages)를 실행할 수 있는 환경을 제공
Spring에는 이녀석이 내장되어 있음 😼

프로그램 내에서 작업을 처리하는 최소 단위


쓰레드가 요청 처리중 다른 요청이 들어오면 다른 요청은 쓰레드가 작업이 끝날 때 까지 기다려야한다.
서버가 여러 클라이언트의 요청을 동시에 처리할 수 있다.
각 요청마다 별도의 쓰레드가 생성되어 작업을 수행
처리 속도가 증가하고, 대기 시간이 감소한다.

서버가 미리 일정 수의 쓰레드를 생성, 관리
각 요청에 대해 새로운 쓰레드를 생성하는 것이 아니라 쓰레드 풀에서 기존의 쓰레드를 할당받아 작업을 수행

⚠️ 주의 ⚠️
멀티쓰레드 관리와 트랜잭션은 다른 개념입니다. 혼동하지 않도록 주의해야 합니다.
멀티쓰레드 관리와 트랜잭션의 차이멀티쓰레드 관리:
여러 쓰레드가 동시에 접근할 수 있는 변수에 대한 일관성 보장
메모리 내에서 여러 쓰레드가 동시에 접근할 수 있는 변수에 관한 문제트랜잭션:
데이터베이스 작업에 대한 일관성, 무결성 보장
데이터베이스 작업에서 여러 작업이 하나의 단위로 묶여서 처리되는 것두 사용자가 동시에 상품의 재고를 줄이는 요청을 했다?
WAS의 멀티쓰레드 처리:
- 두 사용자가 동시에 재고를 줄이려는 요청
- WAS는 각각의 요청을 별도의 쓰레드에서 처리하며, 이때 각각의 쓰레드는 독립적으로 실행
- 멀티쓰레드 환경에서 WAS는 쓰레드 간의 데이터 충돌을 방지하기 위해, 공유 변수에 대한 접근 제어
개발자의 트랜잭션 관리:
- 각 쓰레드는 데이터베이스에서 재고 값을 조회, 이를 수정한 후 다시 저장 하려고 함
- 개발자는 이 과정에서 트랜잭션을 사용해, 두 쓰레드가 동일한 재고 값을 동시에 수정하지 않도록 해야함
- 트랜잭션이 적용된 작업이기 때문에, 한 쓰레드가 재고를 줄이는 작업을 완료하기 전까지 다른 쓰레드는 재고를 수정할 수 없습니다.

서버에 저장된 그대로 클라이언트에게 제공되는 리소스
클라이언트의 요청에 따라 서버에서 실시간으로 생성되거나 조정되는 리소스
인하대학교 컴퓨터공학과/공지사항: 모든 학생에게 일괄적인 HTML 페이지 제공 (정적 리소스)
iClass/수강정보: 학생별, 학기별로 수강하는 수업에 대한 정보 제공 (동적 리소스)
서버사이드 랜더링은 서버에서 HTML을 생성하여 클라이언트에게 제공하는 방식
클라이언트는 서버로부터 완성된 HTML을 받아 브라우저에 표시
장점:
단점:
클라이언트 사이드 랜더링은 클라이언트가 브라우저에서 JavaScript를 실행하여 웹 페이지를 생성
서버는 주로 데이터를 제공하고, 클라이언트는 그 데이터를 사용하여 동적으로 콘텐츠를 렌더링
장점:
단점:
디스패처 서블릿은 스프링 MVC에서 중앙 컨트롤러 역할을 수행하는 서블릿
모든 요청을 처리하다보니 정적 리소스에 대한 요청마저 모두 가로챔
정적 리소스를 불러오지 못하는 상황도 발생하곤 했음
모든 요청에 대해서 저런 URL을 붙여주어야 하므로 직관적인 설계가 될 수 없음


결국 Spring 개발자가 요청을 최초에 받는 지점은 Controller.
@RequestMapping은 Spring에서 HTTP 요청을 특정 메소드에 매핑하기 위해 사용
URL 패턴, HTTP 메소드, 파라미터 등 다양한 속성을 지정
@RequestMapping(value = "/members/new", method = RequestMethod.GET)
public String joinForm() {
return "joinform";
}
@GetMapping: HTTP GET 요청 처리
@PostMapping: HTTP POST 요청 처리
@PutMapping: HTTP PUT 요청 처리
@DeleteMapping: HTTP DELETE 요청 처리
@PatchMapping: HTTP PATCH 요청 처리
@GetMapping("/members/new")
public String joinForm() {
return "joinform";
}
@PostMapping("/members/new")
public String handlePostRequest(@RequestBody MyRequestBody requestBody) {
// 처리 로직
return "redirect:/";
}
PathVariable은 URL 경로의 일부로 전달된 값을 메소드의 파라미터로 사용
URL 템플릿에서 경로 변수와 메소드 파라미터를 연결
@PathVariable 로 사용
GET /users/123
@GetMapping("/users/{userId}")
public String getUser(@PathVariable String userId) {
// userId를 사용한 처리 로직
return "view name";
}
쿼리 스트링으로 전달된 파라미터를 메소드의 파라미터로 사용
URL의 ? 뒤에 붙는 파라미터들
@RequestParam 로 사용
GET /search?query=땅울림
@GetMapping("/search")
public String search(@RequestParam String query) {
// query 파라미터를 사용한 처리 로직
return "searchResults";
}
HTML 폼을 통해 POST 요청으로 전달된 데이터
@ModelAttribute를 사용하여 폼 데이터를 객체로 사용
POST /submit
name=이승철&email=soohwanZZANG@naver.com
@PostMapping("/submit")
public String submitForm(@ModelAttribute MyFormData formData) {
// formData를 사용한 처리 로직
return "resultPage";
}
JSON 또는 XML 형식으로 전달된 데이터를 DTO (Data Transfer Object) 로 매핑
주로 POST 또는 PUT 요청에서 사용
POST /submit HTTP/1.1
{
"id": 1,
"name": "이승철",
"email": "soohwanZZANG@naver.com"
}
@RequestBody
@PostMapping("/submit")
public String submitForm(@RequestBody requestBody) {
// formData를 사용한 처리 로직
return "resultPage";
}
그동안은 view의 경로명을 return
여러 방법이 있지만 하나만 소개
직접 http response body를 만드는 방식
@GetMapping("/users/{userId}")
public ResponseEntity<MemberDTO> getUser(
@PathVariable String userId) {
// userId를 사용한 처리 로직
MemberDTO memberDTO = makeDTO();
return ResponseEntity.ok(memberDTO);
}
시나리오 추가 : 테스트 데이터가 아니라 실제 서비스 데이터라면?
도메인 주소 해석
웹 브라우저는 DNS(Domain Name System) 조회를 수행
(사용자가 웹 브라우저에 입력한 도메인 주소를 해석)
이 과정에서 도메인 이름을 기반으로 해당 서버의 IP 주소를 검색
TCP 연결 설정
DNS 조회가 완료되면, 브라우저는 해당 IP 주소로 웹 서버와의 연결을 시도한다.
HTTP 요청 전송
브라우저는 설정된 TCP 연결을 통해 HTTP 요청을 서버로 전송
사용자가 특정 웹 페이지를 요청 -> 웹 서버(localhost)는 해당 페이지에 대한 HTML 파일을 클라이언트에 응답
이후 브라우저는 이 HTML 파일을 렌더링
form-data 형태로 HTTP POST 요청의 body에 담아 서버로 전송| POST /deposit HTTP/1.1 Host: www.example.com |
|---|
| 이름=땅울림&보너스선택=정률보너스&입금할_금액=10000 |
컨트롤러는 요청된 작업을 처리하기 위해 비즈니스 로직을 수행
일반적으로 service 컴포넌트에 비드니스 로직 위임
동일한 사용자에게 동시에 보너스나 입금 처리가 발생할 수 있음
응답이 단순 경로가 아니라면?
[예시]
{ "message": "입금이 성공적으로 처리되었습니다.", "name": "땅울림", "잔액": 20000 }클라이언트에 적당한 반환값을 반환한다.
핸들러 어댑터는 컨트롤러에서 반환 값을 받아 처리
Dispatcher Servlet은 최종적으로 핸들러 어댑터가 처리한 결과를 클라이언트에게 반환