컨트롤러란?
- 요청을 할 때마다 Java 파일이 호출
- 요청이 종류가 3개이면 3개의 Java 파일이 필요
- 하나의 Java파일에서 모든 요청을 받는 FrontController을 사용
- 너무 많은 요청이 한곳으로 모이는 것을 방지하기 위해 도메인 별로 분기
- 분기의 일은 Servlet Dispatcher가 해준다.- 스프링부트는 이미 만들어져있음
http 4가지 요청 방식
클라이언트가 웹서버에 요청한다.
웹서버는 DB에 SELECT, INSERT, UPDATE, DELETE 요청을 해서 응답한다.
- GET(동사) - 데이터 요청 ( GET 요청은 주로 데이터를 요청하고 가져오는 데 사용 )
- POST(동사) - 데이터 전송
- PUT(동사) - 데이터 갱신
- DELETE(동사) -데이터 삭제
http://IP주소/user/login - /user/login 이 앤드포인트다.
이것을 get요청을 하면 "user의 로그인 필요시 정보를 줄래" 라고 웹서버에게 하는 요청이다.
웹서버는 DB에 select 요청을 한다.
DB는 웹서버에게 응답하고 웹서버는 클라이언트에게 다시 응답한다.
이 때 클라이언트가 웹 브라우저라면 .html로 응답하면 좋다. 왜냐하면 웹 브라우저는 .html을 읽는 해석기이기때문이다.
이 파일이 아니라 문자열도 응답해줄 수 있다. 이것은 파일이 아닌 데이터다. 핸드폰은 .html파일을 인식하지 못하기 때문에 데이터로 응답받아야한다.
- @Controller // File을 응답하는 컨트롤러 (클라이언트가 브라우저면 .hmtl 파일을 응답하는 것이 좋다.)
- @RestController // Data를 응답하는 컨트롤러 (클라언트가 핸드폰이면 data를 응답하는 것이 좋다.)
package com.photogram.web;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HttpController {
@GetMapping("/get")
public String get() {
return "<h1>Get 받음</h1>";
}
@PostMapping("/post")
public String post() {
return "post 받음";
}
@PutMapping("/put")
public String put() {
return "put 받음";
}
@DeleteMapping("/delete")
public String delete() {
return "delete 받음";
}
}
나머지 post / put / delete 요청은 브라우저에서 확인이 불가하므로 postman을 통해 확인하였다.
http 쿼리 스트링(querystring), 주소 변수 매핑(path variable)
- 구체적인 데이터 요청시에 쿼리스트링이나 주소 변수 매핑이 필요하다.
- 스프링부트에서는 주소 변수 매핑을 주로 사용한다. 훨씬 편리하다.
@RestController
public class QueryPathController {
@GetMapping("/chicken")
public String chickenQuery(String type) {
return type + " 배달갑니다.(쿼리스트링)";
}
@GetMapping("/chicken/{type}")
public String chickenPath(@PathVariable String type) {
return type + " 배달갑니다.(주소 변수 매핑)";
}
}
쿼리스트링
주소 변수 매핑
주소변수매핑이 훨씬 가독성이 좋고 편리한것을 확인하였다.
http body 데이터 전송하기
HTTP 헤더의 Content-Type은 전송되는 데이터의 유형을 나타낸다. 이것은 받는 측에게 전송된 데이터를 어떻게 해석해야 하는지를 알려준다. 여기에는 데이터의 종류와 형식이 포함된다.
비유를 사용하여 설명하겠다.
자루( 데이터를 담고 있는 바디(body) )안에 쌀( 전송되는 데이터 )을 전달하기위해 창고( 서버 )에 갔다.창고지기( 서블릿 컨테이너(톰캣) )에게 쌀을 주고 그냥 돌아가버리면 창고지기는 그 자루의 내용물이 무엇인지 알 수 없어 자루를 풀어서 일일히 내용물을 확인해야한다. 이것이 반복되면 계속 확인하는 과정을 거쳐야한다.
창고지기가 어떤 종류의 곡식을 가져오는지 종이( HTTP 헤더 )에 써서 같이 주어야하고 이것을 주지 않으면 무시하는 것으로 바꾸었다. 그래서 창고에 쌀을 두려면 자루안에 든 쌀, 쌀을 명시한 종이( HTTP 헤더의 Content-Type ) 2개가 필요하게 되었다.
즉 HTTP 프로토콜에서는 요청과 응답의 본문(body)에 포함된 데이터의 유형을 명시하기 위해 Content-Type 헤더를 사용한다. 이는 받는 쪽에서 데이터를 올바르게 해석하고 처리하는 데 중요한 역할을 한다. 보통 POST 및 PUT 요청과 함께 바디 데이터를 전송할 때 사용됩니다. 반면에 DELETE와 GET 요청은 바디 데이터를 전송하지 않기 때문에 Content-Type을 명시할 필요가 없다.
스프링 부트는 기본적으로 클라이언트로부터 받은 데이터를 x-www-form-urlencoded 형식으로 파싱합니다. 이는 주로 웹 양식(form) 데이터를 전송할 때 사용되는 방식입니다.
- x-www-form-urlencoded
- 데이터는 "key=value" 형식으로 인코딩되며 여러 개의 키-값 쌍이 "&"로 구분
- 일반적으로 웹 양식에서 사용자로부터 입력된 데이터를 전송하는 데 사용
- ex) "username=John&password=12345"
- plain/text
- 텍스트 데이터를 평문으로 전송하는 데 사용
- 주로 간단한 텍스트 메시지나 로그 데이터와 같은 텍스트 정보를 전송
- ex) 안녕
- application/json
- JSON 형식의 데이터를 전송
- 중괄호 "{ }"로 둘러싸인 형태이며, 키와 값 사이에는 콜론 ":"으로 구분되고, 각 쌍은 쉼표로 구분
- {"username": "John", "age": 30}
적용
package com.photogram.web;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.photogram.domain.User;
@RestController
public class HttpBodyController {
private static final Logger log = LoggerFactory.getLogger(HttpBodyController.class);
@PostMapping("/body1")
public String xwwwformurlencoded(String username) {
log.info(username);
return "key=value 전송옴";
}
@PostMapping("/body2")
public String textplain(@RequestBody String data) {
log.info(data);
return "text/plain 전송옴";
}
@PostMapping("/body3")
public String applicationjson(@RequestBody String data) {
log.info(data);
return "json 전송옴";
}
@PostMapping("/body4")
public String applicationjsonToObject(@RequestBody User user) {
log.info(user.getUsername());
return "json 전송옴";
}
}
Postman을 통해 알아보기
1. x-www-form-urlencoded
스프링 부트는 기본적으로 어떤 데이터가 들어오면 x-www-form-urlencoded타입으로 파싱하기 때문에
public String xwwwformurlencoded(String username) 의 동일한 username 매개변수로 바로 받을 수 있다.
만약 String username1으로 작성 시 데이터를 받지 못한다.
2. plain/text
3. application/json
http 요청을 json으로 응답하기
문자열로 수동으로 직렬화한 후 반환 vs 객체 자체를 반환하여 스프링 부트가 자동으로 JSON으로 직렬화(이렇게 쓰임)
package com.photogram.domain;
public class User {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
@RestController
public class HttpResponseJsonController {
@GetMapping("/resp/json/object")
public String respJsonObject() {
User user = new User();
user.setUsername("홍길동");
String data = "{\"username\":\""+user.getUsername()+"\"}";
return data;
}
@GetMapping("/resp/json/javaobject")
public User respJsonJavaObject() {
User user = new User();
user.setUsername("홍길동");
return user; // MessageConverter가 자동으로 JavaObject를 Json으로 변경해서 통신을 통해 응답한다.
}
}
- 스프링 부트가 기본적으로 내장된 MessageConverter가 자동으로 JavaObject를 Json으로 변경해서 통신을 통해 응답한다.
- @RestControler 일때만 MessageConverter가 작동한다.
http 요청을 file로 응답하기
- .txt 파일 응답하기 (기본경로는 resource/static)
- 스프링부트가 지원하는 .mustache 파일 응답하기
- 스프링부트가 버린 .jsp 파일 응답하기
.jsp와 .mustache 파일은 템플릿 엔진을 가지고 있다.
템플릿 엔진이란 html 파일에 java 코드를 쓸 수 있다.
HTML 파일에는 일반적으로 자바 코드를 직접 삽입할 수 없다. 이는 웹 브라우저가 HTML 파일을 해석할 때 자바 코드를 이해하지 못하기 때문이다. 따라서 HTML 파일을 클라이언트에게 제공하면, 웹 브라우저는 해당 HTML을 그대로 문자열로 해석하여 표시하게 된다. 이는 개발자가 의도한 방식이 아니다.
이러한 문제를 해결하기 위해 서버 측에서는 템플릿 엔진을 사용한다. 클라이언트가 index.jsp와 같은 템플릿 파일을 요청하면, 서버는 이 파일을 템플릿 엔진을 가지고 있는 웹 애플리케이션 서버(WAS)로 전달한다(예: Apache Tomcat). 그런 다음 템플릿 엔진은 JSP 파일에 포함된 자바 코드를 해석하고 실행하여 최종적으로 HTML 파일을 생성한다. 이렇게 생성된 HTML 파일은 자바 코드가 이미 해석되어 있기때문에 웹 브라우저를 통해 응답받은 HTML은 정상적으로 표시된다. 즉 서버 측에서는 템플릿 엔진을 사용하여 자바 코드를 포함한 동적인 웹 페이지를 생성할 수 있다. 이를 통해 웹 애플리케이션은 보다 동적이고 유연한 사용자 경험을 제공한다.
WAS : Web Application이 실행 될 수 있는 환경을 제공하는 Server
WAS(Tomcat)의 구성
(1) Web server
- Client로부터는 요청을 받고 , 정적인 결과를 생성하여 응답을 해준다.
- Client가 동적인 웹 페이지를 요청 할시 Web Container를 통해 동적 페이지 결과를 생성하여 응답한다.
(2) Web Container
- 동적으로 페이지를 생성하여, Web Server에 전달해 준다.
- 동적으로 페이지를 처리함으로써 사용자 마다 다른 결과로 응답이 가능하다
WAS 개념 출처: https://doitnow-man.tistory.com/entry/jsp-%ED%99%88%ED%8E%98%EC%9D%B4%EC%A7%80-%EB%A7%8C%EB%93%A4%EA%B8%B0-5%ED%83%84-%EC%95%84%ED%8C%8C%EC%B9%98-%ED%86%B0%EC%BA%A3WAS%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9B%B9-%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95
HttpRespController.java
package com.photogram.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller // 파일을 리턴할것이기때문에 @Controller
public class HttpRespController {
// 프레임워크 사용(틀이 이미 정해져 있음)-일반 정적파일은 resource/static폴더내부가 디폴트경로
@GetMapping("/txt")
public String txt() {
return "a.txt";
}
// /static/b.mustache
// 자바코드 해석을 안함-다운로드 받아져버림(사용안하는 방법)
@GetMapping("/mus1")
public String mus1(){
return "b.mustache";
}
// /template/b.mustache
// 머스테치 템플릿 엔진 라이브러리 등록 완료
// templates 폴더 안에 .mustache을 나두면 확장자 없이 파일명만 적으면 자동으로 찾아감
@GetMapping("/mus2")
public String mus2(){
return "b";
}
@GetMapping("/jsp")
public String jsp(){
return "c";
}
}
application.yml
spring:
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
pom.xml
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency><!-- 추가하지 않을 시 404에러 --!>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
jsp 파일에 java 코드 사용해보기
템플릿 엔진을 쓰는 이유? 자바코드를 쓰기 위해서이다.
예를 들어, 위의 JavaToJspController 클래스에서는 Spring MVC 프레임워크를 사용하여 HTTP GET 요청이 /jsp/java/model 경로로 들어오면 jspToJavaToModel 메서드가 실행된다. 이 메서드는 Model 객체를 파라미터로 받아서 사용자 객체를 생성하고, 해당 사용자의 이름을 모델에 추가한다. 그런 다음 "e"라는 이름의 뷰(HTML 템플릿)를 반환한다. 이 "e"라는 이름의 뷰는 템플릿 엔진에 의해 해석되어 최종적으로 클라이언트에게 전달될 HTML로 변환된다. 이 때 템플릿 엔진은 Model에 추가된 데이터를 이용하여 동적인 컨텐츠를 생성한다.
@Controller
public class JavaToJspController {
@GetMapping("/jsp/java/model")
public String jspToJavaToModel(Model model) { // 함수의 파라미터에 Model을 선언
User user = new User();
user.setUsername("nana");
model.addAttribute("username", user.getUsername()); // addAttribute 함수로 전달
return "e";
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>This is e</h1>
<h3>${username}</h3>
</body>
</html>
HTTP 요청 재분배하기 - redirection
- HTTP 응답 코드 300번대
- 다른 주소로 요청을 분배
리다이렉션이란 클라이언트의 요청이 들어왔을 때, 해당 요청을 받은 서버가 클라이언트에게 다른 URL로 이동하라는 명령을 내리는 것을 말한다. 이는 요청한 리소스의 URI가 일시적으로 변경되었음을 클라이언트에게 알리는 것이다.
리다이렉션은 중복되는 코드를 재사용하는 장점이 있다. 예를 들어, 여러 페이지에서 동일한 로직이 필요할 때 리다이렉션을 사용하여 해당 로직을 공유할 수 있다.
리다이렉션은 클라이언트와 서버 간의 상호작용에서 중요한 역할을 한다.
- URL 재작성: 서버 측에서 URL을 새로운 위치로 재작성할 필요가 있을 때 사용
- 에러 처리: 예를 들어, 사용자가 요청한 페이지를 찾을 수 없는 경우 404 오류를 반환하는 대신, 사용자를 다른 유사한 페이지로 리다이렉트
- 세션 관리: 사용자가 로그인하거나 특정 작업을 수행할 때 세션을 설정하고, 이후에는 세션을 유지하면서 사용자를 다른 페이지로 리다이렉트
리다이렉션은 서버 측에서 HTTP 응답 코드를 사용하여 클라이언트에게 전달된다. 일반적으로 300번대 상태 코드를 사용한다.
- 301 Moved Permanently: 영구적으로 리소스가 새로운 위치로 이동
- 302 Found (또는 302 Found): 일시적으로 리소스가 다른 위치에 있음을 의미
- 307 Temporary Redirect (또는 307 Temporary Redirect): 302와 유사하지만, 리다이렉트된 요청은 동일한 메서드(예: GET 또는 POST)와 페이로드를 사용하여 재전송
* 페이로드 : 클라이언트가 서버에 전송하는 데이터
POST 요청에서 양식 데이터나 JSON 형식의 데이터 등이 될 수 있다. 마찬가지로, HTTP 응답에서 페이로드는 서버가 클라이언트에게 전송하는 데이터를 나타낸다. 이는 HTML 문서, JSON 데이터, 이미지, 파일 등이 될 수 있다.
@Controller
public class HttpRedirectionController {
@GetMapping("/home")
public String home() {
return "home";
}
@GetMapping("/away")
public String away() {
return "redirect:/home"; // 리다이렉션, @RestContorller에서는 적용안됨
}
}
/away에서 /home으로 리다이렉션할 때, 서버는 클라이언트에게 302 Found 응답을 보내고, Location 헤더에 새로운 URL(/home)을 포함시킨다. 클라이언트는 이 응답을 받으면 새로운 URL(/home)로 요청을 보낸다.
* Location 헤더 : HTTP 응답 헤더의 일종으로, 클라이언트에게 리다이렉션된 리소스의 새로운 URL을 알려줌
'Spring Boot' 카테고리의 다른 글
yml 파일 설정 및 이해 (0) | 2024.03.23 |
---|---|
[스프링부트 개념정리] 필터란 무엇인가 (0) | 2024.03.05 |