SpringBoot 어노테이션

semin Ryu·2024년 6월 10일
0

스프링부트를 공부하면서 자주 사용되는 어노테이션 중 몇 가지를 간단히 설명하겠습니다. 이 어노테이션들은 주로 Java 클래스의 속성을 다룰 때 유용하게 사용됩니다.

@Getter / @Setter

  • Java 클래스의 각 필드에 대한 getter 및 setter 메소드 자동으로 생성
  • Lombok이 제공

@ToString

  • 해당 클래스의 인스턴스를 문자열로 변환할 수 있는 toString()메소드 자동으로 생성
  • Lombok이 제공

@Builder

  • 오브젝트 생성을 위한 디자인 패턴
  • 생성자에서 인자가 많을때 고려해볼 수 있는 것
  • Lombok이 제공
Bag bag = Bag.builder()// Builder 어노테이션으로 생성된 빌더 클래스 생성자
			.name("name")
        	.money(1000)
        	.memo("memo")
        	.build(); // build() 가 객체를 생성해 돌려줌

@NoArgsConstructor

  • 매개변수가 없는 생성자를 구현해준다

@AllArgsConstructor

  • 클래스의 모든 멤버변수를 매개변수로 받는 생성자를 구현해준다.

@RequiredArgsConstructor

  • 필드 중 final이나 @NotNull이 설정된 변수를 매개변수로 갖는 생성자를 자동 생성

@EqualsAndHashCode

  • 객체의 동등성(Equality)과 동일성(Identity)을 비교하는 연산 메서드 생성
    • equals() : 두 객체의 내용이 같은지 동등성을 비교
    • hashCode() : 두 객체가 같은 객체인지 동일성을 비교

@Data

  • @Getter, @Setter, @ToString, @EqualsAndHashCode @RequiredArgsConstructor
    • 위 5 가지의 어노테이션을 합쳐 놓은 것

@RequestMapping

@RestController // Rest API를 구현하므로 RestController 사용
@RequestMapping("test") // 리소스
public class TestController {

    @GetMapping
    public String testController(){
        return "Hello World!";
    }

    @GetMapping("/testGetMapping") // /test/testGetMapping
    public String testControllerWithPath(){
        return "Hello World! testGetMapping";
    }
}

@PathVariable

  • URL 요청으로 들어온 전달 값을 Controller의 매개변수로 가져오는 어노테이션
  • /{id}와 같이 URI의 경로로 넘어오는 값을 변수로 받아올 수 있다.
  • /{id}는 경로로 들어오는 임의의 숫자 또는 문자를 변수 id에 매핑하라는 뜻
  • required = false는 매개변수가 꼭 필요한 것 아니라는 뜻
  • value = “id” 이런 식으로 명시적으로 해주어야함
    • 버전 업그레이드 되면서 해주지 않으면 오류가 발생
@GetMapping("/{id}")
public String testControllerWithPathVariables(@PathVariable(value = "id", required = false) int id){
		return "Hello World ID" + id;
}

@RequestParam

  • RequestParam을 이용하면 ?id={id}와 같이 요청 매개변수로 넘어오는 값 변수로 받아올 수 있다.
    • Ex) localhost:8080/test/testRequestParam?id=123
@GetMapping("/testRequestParam")
public String testControllerWithPathVariables(@RequestParam(value = "id", required = false) Integer id){
    return "Hello World ID" + id;
}

@RequestBody

  • 기본 자료형이 아닌 오브젝트처럼 복잡한 자료형을 통째로 요청에 보내고 싶은 경우

DTO 생성

@Data
public class TestRequestBodyDTO {
    private int id;
    private String message;
}

RequestBody 매개 변수 추가

@RestController // Rest API를 구현하므로 RestController 사용
@RequestMapping("test") // 리소스
public class TestController {

	  @GetMapping("/testRequestBody")
	  public String testControllerRequestBody(@RequestBody TestRequestBodyDTO testRequestBodyDTO){
		    
	      return "Hello World ID" + testRequestBodyDTO.getId() + "Message : " + testRequestBodyDTO.getMessage();
  }
  • @RequestBody TestRequestBodyDTO testRequestBodyDTO
    • @RequestBody로 날아오는 JSON을 TestRequestBodyDTO 오브젝트로 변환해 가져오라는 뜻

@RestController

  • Controller + ResponseBody
  • 메서드가 리턴할 때 스프링은 리턴된 오브젝트를 JSON 형태로 바꾸고 HttpResponse에 담아 반환

ResponseDTO

@Data
@Builder
public class ResponseDTO<T> {
    private List<T> data;
}

Controller

@GetMapping("/testResponseBody")
public ResponseDTO<String> testControllerResponseBody(){
    List<String> list = new ArrayList<>();
    list.add("Hello World! I'm ResponseDTO");
    ResponseDTO<String> response = ResponseDTO.<String>builder().data(list).build();
    return response;
}

@JoinColumn

  • 외래키 매핑
  • name : 매핑할 외래키의 이름을 설정
  • referencedColumnName : 외래키가 참조할 상대 테이블의 칼럼명 지정
  • foreignKey : 외래키 생성하며 지정할 제약조건 설정
    • unique, nullable, insertable, updatable 등

@OneToOne

  • 외래키를 갖는 쪽이 연관관계의 주인
    • 연관관계의 주인이 외래키를 관리(등록, 수정, 삭제)할 수 있어 해당 설정이 중요
  • 주 테이블에 외래키
    • 객체지향 개발자가 선호, JPA 매핑이 편리
    • 장점 - 주 테이블만 조회해도 대상 테이블에 데이터 있는지 확인 가능
    • 단점 - 값이 없으면 외래키에 NULL 허용해야 함, DB 입장에서 치명적
  • 대상 테이블에 외래키
    • 전통적 DB 개발자들이 선호하는 방식, NULL을 허용해야하는 문제 해결
    • 장점 - 일대일에서 일대다 관계로 변경할 때 테이블 구조를 유지할 수 있다
    • 단점 - Ex) 코드상에서 주로 Member 엔티티에서 Locker를 많이 엑세스 하는데 어쩔 수 없이 양방향 매핑을 해야한다
      • 일대일 - 대상 테이블에 외래 키 단방향 매핑을 JPA에서 지원하지 않으므로, 단방향 매핑만 해서는 맴버 객체를 업데이트 했을 때 Locker 테이블에 FK를 업데이트 할 방법이 없다. 따라서 양방향 매핑을 해야 한다.
  • 양방향으로 연관관계 설정되면 ToString을 사용할 때 순환참조 발생.
    • @ToString.Exclude를 사용해 ToString에서 제외 설정 하는 것이 좋음

속성

  • Optional - null인 값 허용 (Boolean 형태)
  • mappedBy - 어떤 객체가 주인인지 표시하는 속성
    • 단방향 - 한 곳에만 @JoinColumn을 한 경우
    • 양방향 - 반대편에 mappedBy를 적용시켜준 경우
@Entity
public class Member{
	  ...
	 
		@OneToOne
		@JoinColumn(name = "locker_id")
		private Locker locker;
}

@Entity
public class Locker {
		...
		@OneToOne(mappedBy = "locker") //Member 엔티티의 locker 필드와 매핑
		@ToString.Exclude
		private Member member; //이 memeber 필드는 읽기 전용 필드
}

@ManyToOne

  • 다대일 관계
  • 아래 예시의 경우 Comment가 Many, Article이 One이다.
  • 연관관계의 주인임을 나타내고 물리 테이블에 있는 article_id 컬럼을 통해 article 필드를 채우기 위해 @JoinColumn을 작성
@Entity
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Comment {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne // Comment 엔티티와 Article 엔티티를 다대일 관계로 설정
    @JoinColumn(name = "article_id") // 외래키 생성, Article 엔티티의 기본키(id)와 매핑
    private Article article; // 해당 댓글의 부모 게시글

		@Column // 해당 필드를 테이블의 속성으로 매핑
    private String nickname;
    
    @Column // 해당 필드를 테이블의 속성으로 매핑
    private String body;
}
  • 단방향인 경우 Article Entity에는 별다른 코드 작성하지 않음.
  • 양방향 매핑을 위해서 Article Entity에 코드를 추가
    • Article Entity는 다수의 Comment Entity를 가질 수 있기 때문에 List 형으로 객체를 정의
    • 조회하려는 정보는 Comment Entity의 article 정보를 참고할 것 이기 때문에 mappedBy를 통해 연관관계를 매핑한다.
      • 생략하면 실행 시 중간 테이블 생성됨
@Entity
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(mappedBy = "article")
    private List<Comment> comment = new ArrayList<>();

		@Column // 해당 필드를 테이블의 속성으로 매핑
    private String title;
    
    @Column // 해당 필드를 테이블의 속성으로 매핑
    private String content;
}

@OneToMany

  • @ManyToOne에는 mappedBy 옵션이 없기 때문에 @OneToMany가 관계의 주인일 경우 양방향 매핑 불가능
    • @ManyToOne은 항상 주인이 된다

@Query

  • 쿼리 처리 지원
  • @Query( value = “쿼리”, nativeQuery = true)
    • value에 쿼리문 작성
    • nativeQuere 속성을 true로 하면 기존 SQL문 사용가능
public interface CommentRepository extends JpaRepository<Comment, Long> {
    @Query(value = "SELECT * FROM comment WHERE article_id =: articleId",
            nativeQuery = true)
    List<Comment> findByArticleId(Long articleId);
}
profile
류세민님의 개발블로그 입니다

0개의 댓글