카테고리 없음

스프링(Spring) 어노테이션들 정리 + ResponseEntity

study5024 2025. 3. 19. 17:31

📌스프링 기본 어노테이션

1️⃣ @Target

@Target 이 선언된 하위 어노테이션이 어떤 범위에 적용되는지 설정한다.

@Target의 ElementType.ANNOTATION_TYPE는 아래 enum상수에 따라 범위를 결정한다 

2️⃣@Component

Spring Bean에 등록하는 역할을 수행한다.

3️⃣@Retention 

 

@Retention 하위의 어노테이션이 얼마나 오래 유지되는지를 결정한다.

4️⃣ @Document

 

Javadoc 등의 문서화 도구에 의해 문서화되어야 함을 나타낸다.

5️⃣ @Indexed 

클래스가 컴포넌트 스캔의 대상으로 Spring Bean에 더 빠르게 등록되도록 도와준다.

 6️⃣ @AliasFor

같은 어노테이션의 속성들끼리 동일한 값을 공유하도록 설정할 수 있음.

@Component
public @interface MyComponent {

    @AliasFor("value")  // 'name'이 'value'와 동일한 역할을 하도록 설정
    String name() default "";

    @AliasFor("name")  // 'value'가 'name'과 동일한 역할을 하도록 설정
    String value() default "";
}

 

하나의 커스텀 어노테이션이 다른 어노테이션을 감싸고 있을 때, 속성을 매핑하여 일관성 유지.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component  // Spring의 @Component 기능을 포함
public @interface MyService { //커스텀 컴포넌트 느낌

    @AliasFor(annotation = Component.class, attribute = "value")  // @Component(value="myService") 와 동일한 효과
    String value() default "";
}


@MyService("myServiceBean")  // @Component("myServiceBean")과 동일한 효과
public class MyServiceBean {}

📌비슷한 어노테이션들

서로 특별한 기능이 있는것이 아니라 사실상 같다 볼 수 있지만 스프링이 역할 구분을 위해 @component를 확장한 것이다

@Component 기본적인 스프링 빈 등록
@Controller Spring MVC 컨트롤러 역할 (추가 기능 없음)
@Service 비즈니스 로직 담당 클래스 표시 (추가 기능 없음)
@Repository DAO(데이터 액세스) 담당 클래스 표시 + 예외 변환 기능 있음

🚨 차이점

  • @Controller와 @Service는 완전히 같은 기능.
  • @Repository만 JPA 같은 DB 연동 시 예외 변환(AOP 기반 트랜잭션 처리) 기능이 추가됨.

📌로그

▪️로그 순서

     Log Level : TRACE > DEBUG > INFO > WARN > ERROR

 

▪️작성법

log.info("문자 trace={}", sparta);// 올바른 작성 방법

log.info("문자 info " + sparta); // 문자 연산을 먼저 해버린다.

 

▪️ application.properties에 아래 내용 추가하여 Log Level 순서를 지정가능 아래로 예시들면 TRACE 부터 시작

# com.example.springbasicannotation 하위 경로들의 로그 레벨을 설정한다.
logging.level.com.example.springbasicannotation=TRACE

 

▪️ 위의 내용을 주석하고 아래를 실행하면 기본값은 info부터 시작이기 떄문에 info,warn,error 다시 info 출력 후 끝난다 

      즉 위에 trace debug는 무시 한다

    // TRACE -> DEBUG -> INFO -> WARN -> ERROR
        log.trace("문자 trace={}", sparta);//실행 x
        log.debug("문자 debug={}", sparta);//실행 x

        // default
        log.info("문자 info={}", sparta);// 문자 연산을 진행하지 않는다.
        log.warn("문자 warn={}", sparta);
        log.error("문자 error={}", sparta);

📌컨트롤러

◾Controller VS RestController 

▪️Controller 

@Controller
public class ViewController {

    @RequestMapping("/view")
    public String example() {
        // logic
        return "sparta"; // ViewName이 return
    }

}

▪️특징

▪️ View를 반환 위에 코드를 예시로 들면 "sparta"를 문자열로 인식 x  👉  ThymeleafViewResolver 에 의해 View Name으로 인식된다. 즉   /sparta로 이동한다

👇 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>

▪️RestController

@RestController
public class ResponseController {

    @RequestMapping("/string")
    public String example() {
        // logic
        return "sparta"; // ViewName이 return 되는게 아니라, String Data가 반환된다.
    }
    
}

▪️특징

▪️View가아닌 데이터를 리턴 해줄 경우에 사용 return 값으로 View를 찾는것이 아니라 HTTP Message Body에 Data를 입력한다

❌ 차이점

둘의 차이는 @ResponseBody가 있고 없고에 따라  뷰 페이지 (ViewResolver가 처리) ,데이터(JSON, XML)를 다룬 다는점

📖 추가

@RestController를 보면 @Controller과 @ResponseBody 어노테이션을 포함 하는데 @RestController@Controller, @ResponseBody  의 역할도 하면서 추가적인 기능이 있다고 보면 된다

그리고 중복선언되는 어노테이션들은 @RestController의 어노테이션이 적용된다

@ResponseBody는  @Target{ElementType.TYPE, ElementType.METHOD} 이지만

@RestController의  @Target{ElementType.TYPE}이 적용 상속받고 재정의 느낌이 있다

 

📌Mapping

 

◾@RequestMapping

특정 URL로 Request를 보내면 들어온 요청을 Controller 내부의 특정 Method와 Mapping 하기 위해 사용한다.

 

◾특징

  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 메서드를 지정하면 지정된것만 허용한다.
    ex) // HTTP Method 는 GET만 허용한다. @RequestMapping(value = "/v1", method = RequestMethod.GET)

◾@GetMapping

내부적으로 @RequestMapping(method = RequestMethod.GET) 을 사용하고 있다.

◾@PostMapping

내부적으로 @RequestMapping(method = RequestMethod.Post) 을 사용하고 있다.

 

📖 정리

RequestMapping는 클래스 레벨에도 적용이가능 하고 Get,Post등등 다른 메소드는

메소드 레벨만 적용가능 대신 축약,직관적으로 사용하고 싶을때 사용 즉 둘을 같이 사용하면

세분화 가능하다. 계층구조로 표현

 

활용 예시 

@RequestMapping("/prefix")
@RestController
public class RequestMappingController {
	// Post, GET, Put, Patch, Delete 모두 가능
	@GetMapping(value = "/v3")
	public String exampleV3() {
		// logic
		return "this is sparta!";
	}

}

 

👉  /prefix/...로 입력된 요청들을 다 처리한다 즉 /prefix/v3 or /prefix/v4 등등 처리 가능

 

📖 속성 설정을 통하여 특정 헤더, 특정 파라미터와 Mapping 하는 법

1️⃣ params 속성

// parms 속성값 추가
@GetMapping(value = "/users", params = "gender=man")

 

http://localhost:8080/users?gender=man  요청 시 호출 gender=man가 있아야 함 없으면 호출 x

규칙

  1. params = "gender"
    • params의 key값은 커스텀이 가능하다
    • value는 없어도 된다.
  2. params = "!gender"
    • gender가 없어야 한다.
  3. params = "gender=man"
    • gender=man 이어야 한다.
  4. params = "gender!=man"
    • params의 value값이 man가 아니여야 한다.
  5. params = {"gender=man", "gender=woman"}
    • 배열로 속성 값을 여러 개 설정이 가능하다.

2️⃣ 특정 Header 매핑

  @PostMapping(value = "/users", headers = "Content-Type=application/json")

 

Content-Typer가 application/json인 경우만 호출

 

3️⃣ MediaType 매핑, consume(수용)

  //consumes 속성값 추가
  @PostMapping(value = "/users", consumes = "application/json") // MediaType.APPLICATION_JSON_VALUE
  
  //위랑 같은 동작
  @PostMapping(value = "/users", consumes = MediaType.APPLICATION_JSON_VALUE)

4️⃣ MediaType 매핑 produces(제공)

요청 헤더의 Accept 값에 따라서 produces 하는 값이 변한다.

consumes 처럼 Media. 으로 가져와서 사용가능

 @GetMapping(value = "/users", produces = "text/plain")
 @GetMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE)

 

 

📌 "클라이언트" 에서 온 데이터를 "서버" 에서 받을 때 처리


  1️⃣ GET, form 데이터 형식으로 왔을 때(Query Param)

 

1️⃣ @PathVariable

  1. 경로 변수를 중괄호에 둘러싸인 값으로 사용할 수 있다.ex) user/{id}
  2. 기본적으로 @PathVariable로 설정된 경로 변수는 반드시 값을 가져야 하며 값이 없으면 응답 상태코드 404 Not Found Error가 발생한다.

@PathVariable 규칙

파라미터 변수명과 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;
	}
	
}

 

▪️ 클래스에도 사용가능

@RequestMapping("/posts/{postId}")
@RestController
public class PathVariableController {
    @GetMapping("/comments/{commentId}")
    public String pathVariableV4(
            @PathVariable Long postId,
            @PathVariable Long commentId
    ) {
        // logic
        String result = "PathvariableV4 결과입니다 postId : " + postId + "commentsId : " + commentId;
        return result;
    }
}

 

2️⃣@RequestParam

URL에서 파라미터 값과 이름을 함께 전달하는 방식으로 주로 HTTP 통신 Method 중 GET 방식의 통신을 할 때 많이 사용한다. @Requestparam을 사용하면 요청 파라미터 값에 아주 쉽고 간편하게 접근(Parameter Binding)할 수 있다.

@Controller
public class RequestParamControllerV2 {

	@ResponseBody
	@GetMapping("/v1/request-param")
	public String requestParamV1 (
					@RequestParam("name") String userName,
					@RequestParam("age") int userAge													
	) {
		// logic
		log.info("name={}", userName);
    log.info("age={}", userAge);
		return "success";
	}

}
  1. @Controller + @ResponseBody
    • View를 찾는 것이 아니라 ResponseBody에 응답을 작성한다(=@RestController)
  2. @RequestParam
    • 파라미터 이름으로 바인딩한다.
  3. @RequestParam(”속성값”)
    • 속성값이 파라미터 이름으로 매핑된다.
  4. “속성값”과 변수명이 같으면 생략이 가능하다.
    required는 파라미터의 필수 값을 설정한다. true면 값이 없으면 400 에러
    String 경우 ""도 true로 봐서 조심
  5. 단순 타입(int, String, Integer 등)이어야 한다.

  6. default 속성 적용
    기본값 설정
@RequestParam(required = true, defaultValue = "sparta") String name,
@RequestParam(required = false, defaultValue = "1") int age

String의 경우 ""도 default 값으로 바꿔줌

 

3️⃣ @ModelAttribute

요청 파라미터를 받아 필요한 Object로 바인딩 해준다. 주로 HTML 폼에서 전송된 데이터를 바인딩하고 HTTP Method POST인 경우 사용된다.

@ModelAttirubte 동작 순서

  1. 파라미터에 @ModelAttribute가 있으면 파라미터인 객체를 생성한다.
  2. 요청 파라미터 이름으로 객체 필드의 Setter를 호출해서 바인딩한다.
    1. 파라미터 이름이 name 이면 setName(value); 메서드를 호출한다. 즉 setter 필요
    2. 파라미터 이름과 필드 이름이 반드시 같아 한다!
    3. 입력값이 맞지 않는 경우 오류나서 검증필요

📖GET vs form data 차이

둘다 서버로 왔을 떄는 Query Strimg 형식으로 같지만 보낼 때 차이가 있다 

 

◾GET 👉 /user?name=이름&age=25

 

form data 👇

<form action="/user" method="post">
    <input type="text" name="name" value="이름">
    <input type="number" name="age" value="25">
    <button type="submit">전송</button>
</form>

//서버에선
POST /user HTTP/1.1
Content-Type: application/x-www-form-urlencoded

name=이름&age=25

 

👉   form 형식이 보안에 좋아서 중요한 데이터는 form 간단한건 get 사용한다

📌 "클라이언트" 에서 온 데이터를 "서버" 에서 받을 때 처리

2️⃣ Json, XML, TEXT 형식, REST API에서 POST, PUT 요청을 처리할 때

 

1️⃣ @RequestBody

클라이언트가 보낸 HTTP 요청의 bodyJava 객체로 변환하는 역할 HttpMessageConverterrk 가 해줌

컨트롤러 리턴값을 view이동이아닌  데이터 전달로 사용하고 싶을 떄 사용

2️⃣ @RequestHeader

클라이언트가 요청을 보낼 때, HTTP 헤더에 담긴 값 조회

3️⃣ @ResponseBody

컨트롤러의 메서드 return 값을 HTTP 응답 바디에 직접 포함 HttpMessageConverterrk 가 해줌

 

💠위의 3가지 예시 

@Controller // @RestController = @Controller + @ResponseBody
public class RequestBodyStringController {
	
  @ResponseBody
  @PostMapping("/v5/request-body-text")
  public String requestBodyTextV5(
          @RequestBody String body,
          @RequestHeader HttpHeaders headers
  ) {
      // HttpMessageConverter가 동작해서 아래 코드가 동작하게됨
      String bodyMessage = body;

      return "request header = " + headers + " response body = " + bodyMessage;
  }
}

💠 요청,결과

📖 2가지 경우 차이


1 폼 데이터를 객체로 매핑 GET, POST 요청의 쿼리 파라미터 또는 폼 데이터 (x-www-form-urlencoded) 스프링이 자동으로 객체 필드에 바인딩 폼 데이터 전송, URL 파라미터 바인딩
2 요청 본문(JSON, XML 등)을 객체로 변환 POST, PUT 요청의 Request Body (JSON, XML) HttpMessageConverter를 통해 객체 변환 REST API에서 JSON 데이터를 받을 때 사용

💠추가 @ResponseStatus 

응답에 상태코드 추가해줌 대신 동적으로는 X

 

ResponseEntity<Object>(JSON) 사용 시 동적으로 상태코드 추가 가능.

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

@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);
	}
	
}
  • ResponseEntity<>두 번째 파라미터에 Enum을 사용하여 상태 코드를 바꿀 수 있다.
  • HTTP Message Converter를 통하여 JSON 형태로 변환되어 반환된다.
  • 동적으로 응답 코드를 변경할 수 있다.