<목차>
1. Spring Annotation
-@Slf4j
-@Controller VS @RestController
-Annotation
2. Request Mapping
-@RequestMapping
-@PathVariable
-특정 파라미터 매핑
-Spring이 지원하는 Parameter
@Slf4j
-Slf4j는 인터페이스이고 그 구현체로 Logback 같은 라이브러리를 선택한다.
-실제 개발에서는 Spring Boot가 기본으로 제공하는 Logback을 대부분 사용한다.
*Logging
-Thread 정보, 클래스 이름과 같은 부가 정보를 함께 확인할 수 있다.
-실제 운영 환경에서는 System.out.println();을 사용하여 Console에 정보를 출력하지 않고, 별도의 로깅 라이브러리를 사용하여 로그를 출력한다.
-Log level 설정을 통하여 Error 메세지만 출력하도록 하기도 하고 로그 메세지를 일자별로 모아서 저장하여 외부 저장소에 보관하기도 한다.
*Log Level
Trace > DEBUG > INFO > WARN > ERROR
*사용시 주의점
package com.example.springbasicannotation.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RestController
public class Slf4jController {
@RequestMapping("/logging")
public String logging() {
String sparta = "Sparta";
// TRACE -> DEBUG -> INFO -> WARN -> ERROR
log.trace("문자 trace={}", sparta);
log.debug("문자 debug={}", sparta);
// default
log.info("문자 info={}", sparta);// 문자 연산을 진행하지 않는다.
log.warn("문자 warn={}", sparta);
log.error("문자 error={}", sparta);
log.info("문자 info " + sparta); // 문자 연산을 먼저 해버린다.
return "success";
}
}
# com.example.springbasicannotation 하위 경로들의 로그 레벨을 설정한다.
logging.level.com.example.springbasicannotation=TRACE
*Postman 호출
-Default Level(INFO) API 호출
-출력결과
-level=TRACE
@Controller
VS
@RestController
-Annotation 기반의 Spring에서 Controller(Handler)를 만들 때 사용하는 어노테이션
1. @Controller
package com.example.springbasicannotation.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ViewController {
@RequestMapping("/view")
public String example() {
// logic
return "sparta"; // ViewName이 return
}
}
-View가 있는 경우에 사용한다.
-Template Engine인 Thymeleaf, JSP 등을 사용하는 경우
*Thymeleaf 예시
-SpringBoot build.gradle 의존성 추가
-main/resources/templates가 기본 경로로 설정된다.
-resources/templates/sparta.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Hello</title>
</head>
<body>
<h2>Thymeleaf Template Sample</h2>
</body>
</html>
*동작 순서
-return 값이 String이면 ThymeleafViewResolver에 의해 View Name으로 인식된다.
2. @RestController
package com.example.springbasicannotation.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ResponseController {
@RequestMapping("/string")
public String example() {
// logic
return "sparta"; // ViewName이 return 되는게 아니라, String Data가 반환된다.
}
}
-응답할 Data가 있는 경우에 사용한다.
-현재는 대부분 @RestController를 사용하여 API가 만들어진다. (Restful API)
-return 값으로 View를 찾는 것이 아니라 HTTP Message Body에 Data를 입력한다.
-View가 아닌 HTTP Message Body에 Data가 들어가는 이유는 @Responsebody 와 관련이 있다.
*동작 순서
*호출 결과
Annotation
자세히 보기
1. @Component
-Spring Bean에 등록하는 역할을 수행한다.
- Spring Bean은 애플리케이션의 구성 요소를 정의하는 객체이다.
- WAS가 Servlet 코드를 읽어 컨테이너에 등록 → Servlet Container 참고
-@Indexed
- 클래스가 컴포넌트 스캔의 대상으로 Spring Bean에 더 빠르게 등록되도록 도와준다.
2. @Target
-@Target이 선언된 하위 어노테이션이 어떤 범위에 적용되는지 설정한다.
-Element Type Enum 속성
-각각의 Enum 마다 적용되는 범위가 상단에 주석으로 설명되어 있다.
3. @Retention
-@Retention 하위의 어노테이션이 얼마나 오래 유지되는지를 결정한다.
-RetentionPolicy Enum 속성
-SOURCE
- 소스 코드(.java)에서만 유지된다.
- 컴파일러에 의해 클래스 파일로 저장되지 않는다.
-CLASS
- 컴파일된 클래스 파일(.class)에 저장되지만, JVM이 실행 시 읽지 않는다.(주석과 같음)
- Defalt 값이다.
-RUNTIME
- 클래스 파일(.class)에 저장되고, JVM에 의해 런타임 시점에 읽을 수 있다.
- 실제 런타임 시점의 코드에 반영되어 영향을 준다.
4. @Documented
-Javadoc 등의 문서화 도구에 의해 문서화되어야 함을 나타낸다.
다시보는
@Controller
VS
@RestController
-개발에서 우선순위는 항상 자세히 선언된것이 우선순위가 높다.
1. @Controller 다시보기
@Target(ElementType.Type)
- Class, Interface, Annotation, Enum, Record Declarations(Java16)에 적용할 수 있다.
@Retention(RetentionPolicy.RUNTIME)
- 클래스 파일(.class)에 저장되고, JVM에 의해 런타임 시점에 읽을 수 있다.
@Document
- Javadoc 등의 문서화 도구에 의해 문서화되어야 함을 나타낸다.
@Component
- Spring Bean에 등록한다.
- 싱글톤으로 관리된다.
2. @RestController 다시보기
-@Controller에 @ResponseBody가 결합된 어노테이션
-@RestController는 @Controller와 달리 각 메서드마다 @ResponseBody를 추가하지 않아도 된다.
+@Controller에 동일한 Target이 선언되어 있는데 왜 중복으로 선언이 되어 있나?
*@ResponseBody 자세히 보기
-@Target{ElementType.TYPE, ElementType.METHOD} 이지만, @RestController 는 @Target(ElementType.TYPE)이기 때문에 TYPE 범위에만 @ResponseBody가 적용된다.
@RequestMapping
-특정 URL로 Request를 보내면 들어온 요청을 Controller 내부의 특정 Method와 Mapping 하기 위해 사용한다.
-Client로부터 요청이 왔을 때 어떤 Controller가 호출될 지 Mapping 하는 것은 단순히 URL로 Mapping 하는것이 아니라 여러가지 요소(URL, Method 등)를 조합하여 Mapping한다.
*@RequestMapping
1. Spring Boot 3.0 버전 이하
-URL path /example, /example/ 모두 허용(Mapping)한다.
2. Spring Boot 3.0 버전 이상(현재 버전)
-URL path /example 만 허용(Mapping)한다.
3. 속성 값들을 설정할 때 배열 형태로 다중 설정이 가능하다.
-ex) @RequestMapping({"/example","/example2","/example3"})
4. HTTP Method POST, GET, PUT, PATCH, DELETE, HEAD 모두 허용한다.
5. method 속성으로 HTTP 메서드를 지정하면 지정된 것만 허용한다.
package com.example.springbasicannotation.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
// 응답 데이터를 반환한다.
@RestController
public class RequestMappingController {
// HTTP Method 는 GET만 허용한다.
@RequestMapping(value = "/v1", method = RequestMethod.GET)
public String exampleV1() {
// logic
return "this is sparta!";
}
}
-실행 결과
-만약 속성으로 설정된 HTTP Method로 요청이 오지 않는 다면?
localhost:8080/v1 + POST, PUT, PATCH, DELETE의 경우
*@GetMapping
1. Target(ElementType.METHOD) Method Level에 해당 어노테이션을 적용한다 라는 의미
2. 내부적으로 @RequestMapping(method = RequestMethod.GET)을 사용하고 있다.
-코드 예시
// Post, GET, Put, Patch, Delete 모두 가능
@GetMapping(value = "/v2")
public String exampleV2() {
// logic
return "this is sparta!";
}
-Spring이 제공하는 Annotation들의 내부에 다 선언되어 있다.
-대부분의 필요한 기능들이 이미 만들어져 있다, 사용하면 된다.
-@RequestMapping 보다는 직관적이고 축약된 @GetMapping, @PostMapping 형식을 일반적으로 사용한다.
-실행 결과
-@PostMapping, @PutMapping, @DeleteMapping, @PatchMapping
- 모두 위의 @GetMapping과 같은 구조를 가지고 있다.
*@RequestMapping 사용방법
-@PostMapping, @PutMapping, @DeleteMapping, @PatchMapping의 Target은 Method Level이다.
-@RequestMapping의 Target은 class, method 레벨에 적용이 가능하다.
-Restful API 계층 구조
ex) users/{userId}, category/{categoryId}/product/{productId}
-prefix로 선언할 URL을 class 레벨에 적용하는 것에 주로 사용된다.
@RequestMapping("/prefix")
@RestController
public class RequestMappingController {
// Post, GET, Put, Patch, Delete 모두 가능
@GetMapping(value = "/v3")
public String exampleV3() {
// logic
return "this is sparta!";
}
}
-실행 결과
@PathVariable
-HTTP 특성 중 하나인 비연결성을 극복하여 데이터를 전달하기 위한 방법 중 하나이다.
-URL로 전달된 값을 파라미터로 받아오는 역할을 수행한다.
*@PathVariable
1. 경로 변수를 중괄호에 둘러싸인 값으로 사용할 수 있다.
ex) user/{id}
2. 기본적으로 @PathVariable로 설정된 경로 변수는 반드시 값을 가져야 하며 값이 없으면 응답 상태코드 404 Not Found Error가 발생한다.
3. 최근 Restful API를 설계하는 것이 API의 기준이 되며 해당 어노테이션의 사용 빈도가 높아졌다.
+ Restful API를 설계하게 되면 URL path 만으로 어떤 Resource를 사용하는지, HTTP Method만으로 어떤 기능이 동작되는지 쉽게 알아볼 수 있다.
*Restful API
https://restfulapi.net/resource-naming/
- Create - POST
- Read - GET
- Update - PUT, PATCH
- Delete - DELETE
*Restful API 설계 예시
-postId 글의 comment 댓글 작성
- POST + posts/{postId}/comments
-postId 글의 comment 댓글 전체 조회
- GET + posts/{postId}/comments
-postId 글의 commentId 댓글 단건 조회
- GET + posts/{postId}/comments/{commentId}
-postId 글의 commentId 댓글 수정
- PUT + posts/{postId}/comments/{commentId}
-postId 글의 commentId 댓글 삭제
- DELETE + posts/{postId}/comments/{commentId}
*@PathVariable 규칙
1. 파라미터 변수명과 PathVariable 변수명이 같으면 속성 값 생략 가능
@RequestMapping("/posts")
@RestController
public class PathVariableController {
// postId로 된 post 단건 조회
@GetMapping("/{postId}")
public String pathVariableV1(@PathVariable("postId") Long data) {
// logic
String result = "PathvariableV1 결과입니다 : " + data;
return result;
}
}
-실행결과
-생략
@RequestMapping("/posts")
@RestController
public class PathVariableController {
// 변수명과 같다면 속성값 생략가능
@GetMapping("/{postId}")
public String pathVariableV2(@PathVariable Long postId) {
// logic
String result = "PathvariableV2 결과입니다 : " + postId;
return result;
}
}
-실행결과
2. @PathVariable 다중 사용 가능
@RestController
public class PathVariableController {
@GetMapping("/{postId}/comments/{commentId}")
public String pathVariableV3(
@PathVariable Long postId,
@PathVariable Long commentId
) {
// logic
String result = "PathvariableV3 결과입니다 postId : " + postId + "commentsId : " + commentId;
return result;
}
}
-실행결과
특정 파라미터 매핑
-속성 설정을 통하여 특정 헤더, 특정 파라미터와 Mapping 할 수 있다.
1. Parameter 추가 매핑
-특정 파라미터와 매핑하는 방법
package com.example.springbasicannotation.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ParameterController {
// parms 속성값 추가
@GetMapping(value = "/users", params = "gender=man")
public String params() {
// logic
String result = "params API가 호출 되었습니다.";
return result;
}
}
-실제 URL GET http://localhost:8080/users?gender=man 파라미터가 있어야 호출된다.
-실행결과
-파라미터가 없다면? 400 Bad Request 클라이언트 측 에러
-속성 작성 규칙
- params = "gender"
- params의 key 값은 커스텀이 가능하다.
- value는 없어도 된다.
- params = "!gender"
- gender가 없어야 한다.
- params = "gender = man"
- gender=man 이어야 한다.
- params = "gender != man"
- params의 value 값이 man이 아이여야한다.
- params = {"gende=man", "gender=woman"}
- 배열로 속성 값을 여러개 설정이 가능하다.
2. 특정 Header 매핑
-특정 Header와 매핑하는 방법
@RestController
public class ParameterController {
// headers 속성값 추가
@PostMapping(value = "/users", headers = "Content-Type=application/json")
public String headers() {
// logic
String result = "headers API가 호출 되었습니다.";
return result;
}
}
-Postman → Body → raw → JSON
-Postman → Headers → hidden
-HTTP Header를 사용하기 때문에 Postman으로 테스트해야한다.
ex) key=Content-Type / value = application/json
-실행결과
--속성 작성 규칙은 위 params 속성 값의 규칙과 같다.
3. MediaType 매핑, consume(수용)
-HTTP Header Content-Type(요청)과 매핑된다.
@RestController
public class ParameterController {
// consumes 속성값 추가
@PostMapping(value = "/users", consumes = "application/json") // MediaType.APPLICATION_JSON_VALUE
public String consumes() {
// logic
String result = "consumes API가 호출 되었습니다.";
return result;
}
}
-consumes 속성 value값으로는 이미 Spring에서 제공되는 Enum인 MediaType.APPLICATION_JSON_VALUE 형태로 사용한다.
-Postman → Body → raw → JSON
-Postman → Headers → Content-Type → Value
-파라미터가 없거나 다르다면? HTTP 상태코드 405 Unsupported Media Type Exception 발생
-속성 작성 방법
- consumes="application/json"
- application/json 미디어 타입 허용
- consumes="!application/json"
- application/json 제외 미디어 타입 허용
- consumes="application/*"
- application/ 으로 시작하는 모든 미디어 타입 허용
- consumes="*\/*"
- 모두 허용
4. MediaType 매핑 produces(제공)
-요청 헤더의 Accept 값에 따라서 produces 하는 값이 변한다.
@RestController
public class ParameterController {
// produces 속성값 추가
@GetMapping(value = "/users", produces = "text/plain")
public String produces() {
// logic
String result = "text/plain 데이터 응답";
return result;
}
}
-HTTP 요청 Accept Header에 Media Type이 있어야 한다.
-실행 결과
-위에 나온 모든 MediaType은 Spring이 제공하는 Enum을 사용하면 된다.
ex) produces = "application.json" → produces = MediaType.APPLICATION_JSON_VALUE
Spring이 지원하는 Parameter
-어노테이션 기반 Spring의 Controller는 다양한 파라미터를 쉽게 사용할 수 있도록 지원한다.
-@Controller의 사용 가능한 파라미터 목록 - 공식 문서
-Controller의 사용 가능한 Response 값 목록 - 공식문서
*HTTP 헤더 조회
-Spring에서 요청 Header에 쉽게 접근할 수 있다.
- HttpServletRequest와 같이 파라미터로 다룰 수 있다.
-Controller 예시
// 로깅
@Slf4j
@RestController
public class RequestHeaderController {
@GetMapping("/request/headers")
public String headers(
HttpServletRequest request, // Servlet에서 사용한것과 같음
HttpServletResponse response, // Servlet에서 사용한것과 같음
@RequestHeader MultiValueMap<String, String> headerMap,
@RequestHeader("host") String host,
@CookieValue(value = "cookie", required = false) String cookie,
HttpMethod httpMethod,
Locale locale
) {
// Servlet
log.info("request={}", request);
log.info("response={}", response);
// @RequestHeader
log.info("headerMap={}", headerMap);
log.info("host={}", host);
// @CookieValue
log.info("cookie={}", cookie);
// HttpMethod
log.info("httpMethod={}", httpMethod);
// Locale
log.info("Locale={}", locale);
return "success";
}
}
-Postman API 호출
-Log 출력 결과
- request
- HttpServletRequest 객체 주소 값
- response
- HttpServletRequest 객체 주소 값
- headerMap :
hashMap={
user-agent=[PostmanRuntime/7.35.0],
accept=[*/*],
postman-token=[5f324c1c-7902-4750-9e01-2c4d093e8ad6],
host=[localhost:8080],
accept-encoding=[gzip, deflate, br],
connection=[keep-alive]
}
4. host
- host 정보
5. cookie
- Header의 Cookie 값
6. httpMethod
- 호출에 사용한 HttpMethod
7. Locale
- 위치 정보를 나타내는 헤더
- 우선순위가 존재한다.
+MultiValueMap
-Map과 유사하게 Key, Value 형식으로 구현되어 있지만 하나의 Key가 여러 Value를 가질 수 있다.
-HTTP Header, Request Parameter와 같이 하나의 Key에 여러 값을 받을 때 사용한다.
ex) key1=value&key1=value2
-예시코드
MultiValueMap<String, String> linkedMultiValuemap = new LinkedMultiValueMap();
// key1에 value1 저장
linkedMultiValuemap.add("key1", "value1");
// key1에 value2 저장
linkedMultiValuemap.add("key1", "value2");
// key1에 저장된 모든 value get
List<String> values = linkedMultiValuemap.get("key1");
'내배캠 > Spring' 카테고리의 다른 글
[내일배움캠프/백엔드] 심화 Spring 1주차 강의 (0) | 2024.11.27 |
---|---|
[내일배움캠프/백엔드] 기초 Spring 5주차 강의 (0) | 2024.11.11 |
[내일배움캠프/백엔드] 기초 Spring 3주차 강의 (1) | 2024.11.05 |
[내일배움캠프/백엔드] 기초 Spring 2주차 강의 (3) | 2024.11.04 |
[내일배움캠프/백엔드] 기초 Spring 1주차 강의 3. Web Application (5) | 2024.10.31 |